[BACK]Return to meta.c CVS log [TXT][DIR] Up to [cvs.NetBSD.org] / src / usr.bin / make

Annotation of src/usr.bin/make/meta.c, Revision 1.43

1.43    ! christos    1: /*      $NetBSD: meta.c,v 1.42 2016/01/17 15:30:23 christos Exp $ */
1.15      sjg         2:
1.1       sjg         3: /*
                      4:  * Implement 'meta' mode.
                      5:  * Adapted from John Birrell's patches to FreeBSD make.
                      6:  * --sjg
                      7:  */
                      8: /*
                      9:  * Copyright (c) 2009-2010, Juniper Networks, Inc.
                     10:  * Portions Copyright (c) 2009, John Birrell.
                     11:  *
                     12:  * Redistribution and use in source and binary forms, with or without
                     13:  * modification, are permitted provided that the following conditions
                     14:  * are met:
                     15:  * 1. Redistributions of source code must retain the above copyright
                     16:  *    notice, this list of conditions and the following disclaimer.
                     17:  * 2. Redistributions in binary form must reproduce the above copyright
                     18:  *    notice, this list of conditions and the following disclaimer in the
                     19:  *    documentation and/or other materials provided with the distribution.
                     20:  *
                     21:  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
                     22:  * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
                     23:  * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
                     24:  * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
                     25:  * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
                     26:  * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
                     27:  * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
                     28:  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
                     29:  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
                     30:  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
                     31:  * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
                     32:  */
1.3       sjg        33: #if defined(USE_META)
1.1       sjg        34:
                     35: #ifdef HAVE_CONFIG_H
                     36: # include "config.h"
                     37: #endif
                     38: #include <sys/stat.h>
                     39: #include <sys/ioctl.h>
                     40: #include <libgen.h>
                     41: #include <errno.h>
1.2       sjg        42: #if !defined(HAVE_CONFIG_H) || defined(HAVE_ERR_H)
1.1       sjg        43: #include <err.h>
1.2       sjg        44: #endif
1.1       sjg        45:
                     46: #include "make.h"
                     47: #include "job.h"
                     48:
                     49: #ifdef HAVE_FILEMON_H
                     50: # include <filemon.h>
                     51: #endif
                     52: #if !defined(USE_FILEMON) && defined(FILEMON_SET_FD)
                     53: # define USE_FILEMON
                     54: #endif
                     55:
                     56: static BuildMon Mybm;                  /* for compat */
1.32      sjg        57: static Lst metaBailiwick;              /* our scope of control */
                     58: static Lst metaIgnorePaths;            /* paths we deliberately ignore */
                     59:
                     60: #ifndef MAKE_META_IGNORE_PATHS
                     61: #define MAKE_META_IGNORE_PATHS ".MAKE.META.IGNORE_PATHS"
                     62: #endif
1.1       sjg        63:
                     64: Boolean useMeta = FALSE;
                     65: static Boolean useFilemon = FALSE;
                     66: static Boolean writeMeta = FALSE;
                     67: static Boolean metaEnv = FALSE;                /* don't save env unless asked */
                     68: static Boolean metaVerbose = FALSE;
                     69: static Boolean metaIgnoreCMDs = FALSE; /* ignore CMDs in .meta files */
1.12      sjg        70: static Boolean metaCurdirOk = FALSE;   /* write .meta in .CURDIR Ok? */
1.22      sjg        71: static Boolean metaSilent = FALSE;     /* if we have a .meta be SILENT */
1.1       sjg        72:
                     73: extern Boolean forceJobs;
                     74: extern Boolean comatMake;
1.25      sjg        75: extern char    **environ;
1.1       sjg        76:
                     77: #define        MAKE_META_PREFIX        ".MAKE.META.PREFIX"
                     78:
                     79: #ifndef N2U
                     80: # define N2U(n, u)   (((n) + ((u) - 1)) / (u))
                     81: #endif
                     82: #ifndef ROUNDUP
                     83: # define ROUNDUP(n, u)   (N2U((n), (u)) * (u))
                     84: #endif
                     85:
1.2       sjg        86: #if !defined(HAVE_STRSEP)
                     87: # define strsep(s, d) stresep((s), (d), 0)
                     88: #endif
                     89:
1.1       sjg        90: /*
                     91:  * Filemon is a kernel module which snoops certain syscalls.
                     92:  *
                     93:  * C chdir
                     94:  * E exec
                     95:  * F [v]fork
                     96:  * L [sym]link
                     97:  * M rename
                     98:  * R read
                     99:  * W write
                    100:  * S stat
                    101:  *
                    102:  * See meta_oodate below - we mainly care about 'E' and 'R'.
                    103:  *
                    104:  * We can still use meta mode without filemon, but
                    105:  * the benefits are more limited.
                    106:  */
                    107: #ifdef USE_FILEMON
                    108: # ifndef _PATH_FILEMON
                    109: #   define _PATH_FILEMON "/dev/filemon"
                    110: # endif
                    111:
                    112: /*
                    113:  * Open the filemon device.
                    114:  */
                    115: static void
                    116: filemon_open(BuildMon *pbm)
                    117: {
                    118:     int retry;
                    119:
                    120:     pbm->mon_fd = pbm->filemon_fd = -1;
                    121:     if (!useFilemon)
                    122:        return;
                    123:
                    124:     for (retry = 5; retry >= 0; retry--) {
                    125:        if ((pbm->filemon_fd = open(_PATH_FILEMON, O_RDWR)) >= 0)
                    126:            break;
                    127:     }
                    128:
                    129:     if (pbm->filemon_fd < 0) {
                    130:        useFilemon = FALSE;
                    131:        warn("Could not open %s", _PATH_FILEMON);
                    132:        return;
                    133:     }
                    134:
                    135:     /*
                    136:      * We use a file outside of '.'
                    137:      * to avoid a FreeBSD kernel bug where unlink invalidates
                    138:      * cwd causing getcwd to do a lot more work.
                    139:      * We only care about the descriptor.
                    140:      */
                    141:     pbm->mon_fd = mkTempFile("filemon.XXXXXX", NULL);
                    142:     if (ioctl(pbm->filemon_fd, FILEMON_SET_FD, &pbm->mon_fd) < 0) {
                    143:        err(1, "Could not set filemon file descriptor!");
                    144:     }
                    145:     /* we don't need these once we exec */
1.42      christos  146:     (void)fcntl(pbm->mon_fd, F_SETFD, FD_CLOEXEC);
                    147:     (void)fcntl(pbm->filemon_fd, F_SETFD, FD_CLOEXEC);
1.1       sjg       148: }
                    149:
                    150: /*
                    151:  * Read the build monitor output file and write records to the target's
                    152:  * metadata file.
                    153:  */
                    154: static void
                    155: filemon_read(FILE *mfp, int fd)
                    156: {
                    157:     char buf[BUFSIZ];
1.35      sjg       158:     int n;
1.1       sjg       159:
                    160:     /* Check if we're not writing to a meta data file.*/
                    161:     if (mfp == NULL) {
                    162:        if (fd >= 0)
                    163:            close(fd);                  /* not interested */
                    164:        return;
                    165:     }
                    166:     /* rewind */
1.24      christos  167:     (void)lseek(fd, (off_t)0, SEEK_SET);
1.1       sjg       168:
1.36      sjg       169:     fprintf(mfp, "\n-- filemon acquired metadata --\n");
1.1       sjg       170:
1.35      sjg       171:     while ((n = read(fd, buf, sizeof(buf))) > 0) {
                    172:        fwrite(buf, 1, n, mfp);
1.1       sjg       173:     }
                    174:     fflush(mfp);
1.35      sjg       175:     close(fd);
1.1       sjg       176: }
                    177: #endif
                    178:
1.8       sjg       179: /*
                    180:  * when realpath() fails,
                    181:  * we use this, to clean up ./ and ../
                    182:  */
                    183: static void
                    184: eat_dots(char *buf, size_t bufsz, int dots)
                    185: {
                    186:     char *cp;
                    187:     char *cp2;
                    188:     const char *eat;
                    189:     size_t eatlen;
                    190:
                    191:     switch (dots) {
                    192:     case 1:
                    193:        eat = "/./";
                    194:        eatlen = 2;
                    195:        break;
                    196:     case 2:
                    197:        eat = "/../";
                    198:        eatlen = 3;
                    199:        break;
                    200:     default:
                    201:        return;
                    202:     }
                    203:
                    204:     do {
                    205:        cp = strstr(buf, eat);
                    206:        if (cp) {
                    207:            cp2 = cp + eatlen;
                    208:            if (dots == 2 && cp > buf) {
                    209:                do {
                    210:                    cp--;
                    211:                } while (cp > buf && *cp != '/');
                    212:            }
                    213:            if (*cp == '/') {
                    214:                strlcpy(cp, cp2, bufsz - (cp - buf));
                    215:            } else {
                    216:                return;                 /* can't happen? */
                    217:            }
                    218:        }
                    219:     } while (cp);
                    220: }
                    221:
1.1       sjg       222: static char *
                    223: meta_name(struct GNode *gn, char *mname, size_t mnamelen,
                    224:          const char *dname,
                    225:          const char *tname)
                    226: {
                    227:     char buf[MAXPATHLEN];
                    228:     char cwd[MAXPATHLEN];
                    229:     char *rp;
                    230:     char *cp;
                    231:     char *tp;
                    232:     char *p[4];                                /* >= number of possible uses */
                    233:     int i;
                    234:
                    235:     i = 0;
                    236:     if (!dname)
                    237:        dname = Var_Value(".OBJDIR", gn, &p[i++]);
                    238:     if (!tname)
                    239:        tname = Var_Value(TARGET, gn, &p[i++]);
                    240:
1.8       sjg       241:     if (realpath(dname, cwd))
                    242:        dname = cwd;
                    243:
1.1       sjg       244:     /*
                    245:      * Weed out relative paths from the target file name.
                    246:      * We have to be careful though since if target is a
                    247:      * symlink, the result will be unstable.
                    248:      * So we use realpath() just to get the dirname, and leave the
                    249:      * basename as given to us.
                    250:      */
                    251:     if ((cp = strrchr(tname, '/'))) {
                    252:        if (realpath(tname, buf)) {
                    253:            if ((rp = strrchr(buf, '/'))) {
                    254:                rp++;
                    255:                cp++;
                    256:                if (strcmp(cp, rp) != 0)
                    257:                    strlcpy(rp, cp, sizeof(buf) - (rp - buf));
                    258:            }
                    259:            tname = buf;
1.8       sjg       260:        } else {
                    261:            /*
                    262:             * We likely have a directory which is about to be made.
                    263:             * We pretend realpath() succeeded, to have a chance
                    264:             * of generating the same meta file name that we will
                    265:             * next time through.
                    266:             */
                    267:            if (tname[0] == '/') {
                    268:                strlcpy(buf, tname, sizeof(buf));
                    269:            } else {
                    270:                snprintf(buf, sizeof(buf), "%s/%s", cwd, tname);
                    271:            }
                    272:            eat_dots(buf, sizeof(buf), 1);      /* ./ */
                    273:            eat_dots(buf, sizeof(buf), 2);      /* ../ */
                    274:            tname = buf;
1.1       sjg       275:        }
                    276:     }
                    277:     /* on some systems dirname may modify its arg */
                    278:     tp = bmake_strdup(tname);
                    279:     if (strcmp(dname, dirname(tp)) == 0)
                    280:        snprintf(mname, mnamelen, "%s.meta", tname);
                    281:     else {
                    282:        snprintf(mname, mnamelen, "%s/%s.meta", dname, tname);
                    283:
                    284:        /*
                    285:         * Replace path separators in the file name after the
                    286:         * current object directory path.
                    287:         */
                    288:        cp = mname + strlen(dname) + 1;
                    289:
                    290:        while (*cp != '\0') {
                    291:            if (*cp == '/')
                    292:                *cp = '_';
                    293:            cp++;
                    294:        }
                    295:     }
                    296:     free(tp);
                    297:     for (i--; i >= 0; i--) {
                    298:        if (p[i])
                    299:            free(p[i]);
                    300:     }
                    301:     return (mname);
                    302: }
                    303:
                    304: /*
                    305:  * Return true if running ${.MAKE}
                    306:  * Bypassed if target is flagged .MAKE
                    307:  */
                    308: static int
                    309: is_submake(void *cmdp, void *gnp)
                    310: {
                    311:     static char *p_make = NULL;
                    312:     static int p_len;
                    313:     char  *cmd = cmdp;
                    314:     GNode *gn = gnp;
                    315:     char *mp = NULL;
                    316:     char *cp;
                    317:     char *cp2;
                    318:     int rc = 0;                                /* keep looking */
                    319:
                    320:     if (!p_make) {
                    321:        p_make = Var_Value(".MAKE", gn, &cp);
                    322:        p_len = strlen(p_make);
                    323:     }
                    324:     cp = strchr(cmd, '$');
                    325:     if ((cp)) {
1.40      sjg       326:        mp = Var_Subst(NULL, cmd, gn, FALSE, TRUE);
1.1       sjg       327:        cmd = mp;
                    328:     }
                    329:     cp2 = strstr(cmd, p_make);
                    330:     if ((cp2)) {
                    331:        switch (cp2[p_len]) {
                    332:        case '\0':
                    333:        case ' ':
                    334:        case '\t':
                    335:        case '\n':
                    336:            rc = 1;
                    337:            break;
                    338:        }
                    339:        if (cp2 > cmd && rc > 0) {
                    340:            switch (cp2[-1]) {
                    341:            case ' ':
                    342:            case '\t':
                    343:            case '\n':
                    344:                break;
                    345:            default:
                    346:                rc = 0;                 /* no match */
                    347:                break;
                    348:            }
                    349:        }
                    350:     }
                    351:     if (mp)
                    352:        free(mp);
                    353:     return (rc);
                    354: }
                    355:
                    356: typedef struct meta_file_s {
                    357:     FILE *fp;
                    358:     GNode *gn;
                    359: } meta_file_t;
                    360:
                    361: static int
                    362: printCMD(void *cmdp, void *mfpp)
                    363: {
                    364:     meta_file_t *mfp = mfpp;
                    365:     char *cmd = cmdp;
                    366:     char *cp = NULL;
                    367:
                    368:     if (strchr(cmd, '$')) {
1.40      sjg       369:        cmd = cp = Var_Subst(NULL, cmd, mfp->gn, FALSE, TRUE);
1.1       sjg       370:     }
                    371:     fprintf(mfp->fp, "CMD %s\n", cmd);
                    372:     if (cp)
                    373:        free(cp);
                    374:     return 0;
                    375: }
                    376:
                    377: /*
                    378:  * Certain node types never get a .meta file
                    379:  */
                    380: #define SKIP_META_TYPE(_type) do { \
                    381:     if ((gn->type & __CONCAT(OP_, _type))) {   \
                    382:        if (DEBUG(META)) { \
                    383:            fprintf(debug_file, "Skipping meta for %s: .%s\n", \
                    384:                    gn->name, __STRING(_type));                \
                    385:        } \
                    386:        return (NULL); \
                    387:     } \
                    388: } while (0)
                    389:
                    390: static FILE *
                    391: meta_create(BuildMon *pbm, GNode *gn)
                    392: {
                    393:     meta_file_t mf;
                    394:     char buf[MAXPATHLEN];
                    395:     char objdir[MAXPATHLEN];
                    396:     char **ptr;
                    397:     const char *dname;
                    398:     const char *tname;
                    399:     char *fname;
                    400:     const char *cp;
                    401:     char *p[4];                                /* >= possible uses */
                    402:     int i;
                    403:     struct stat fs;
                    404:
                    405:
                    406:     /* This may be a phony node which we don't want meta data for... */
                    407:     /* Skip .meta for .BEGIN, .END, .ERROR etc as well. */
                    408:     /* Or it may be explicitly flagged as .NOMETA */
                    409:     SKIP_META_TYPE(NOMETA);
                    410:     /* Unless it is explicitly flagged as .META */
                    411:     if (!(gn->type & OP_META)) {
                    412:        SKIP_META_TYPE(PHONY);
                    413:        SKIP_META_TYPE(SPECIAL);
                    414:        SKIP_META_TYPE(MAKE);
                    415:     }
                    416:
                    417:     mf.fp = NULL;
                    418:
                    419:     i = 0;
                    420:
                    421:     dname = Var_Value(".OBJDIR", gn, &p[i++]);
                    422:     tname = Var_Value(TARGET, gn, &p[i++]);
                    423:
                    424:     /* The object directory may not exist. Check it.. */
                    425:     if (stat(dname, &fs) != 0) {
                    426:        if (DEBUG(META))
                    427:            fprintf(debug_file, "Skipping meta for %s: no .OBJDIR\n",
                    428:                    gn->name);
                    429:        goto out;
                    430:     }
                    431:     /* Check if there are no commands to execute. */
                    432:     if (Lst_IsEmpty(gn->commands)) {
                    433:        if (DEBUG(META))
                    434:            fprintf(debug_file, "Skipping meta for %s: no commands\n",
                    435:                    gn->name);
                    436:        goto out;
                    437:     }
                    438:
                    439:     /* make sure these are canonical */
                    440:     if (realpath(dname, objdir))
                    441:        dname = objdir;
                    442:
                    443:     /* If we aren't in the object directory, don't create a meta file. */
1.12      sjg       444:     if (!metaCurdirOk && strcmp(curdir, dname) == 0) {
1.1       sjg       445:        if (DEBUG(META))
                    446:            fprintf(debug_file, "Skipping meta for %s: .OBJDIR == .CURDIR\n",
                    447:                    gn->name);
                    448:        goto out;
                    449:     }
                    450:     if (!(gn->type & OP_META)) {
                    451:        /* We do not generate .meta files for sub-makes */
                    452:        if (Lst_ForEach(gn->commands, is_submake, gn)) {
                    453:            if (DEBUG(META))
                    454:                fprintf(debug_file, "Skipping meta for %s: .MAKE\n",
                    455:                        gn->name);
                    456:            goto out;
                    457:        }
                    458:     }
                    459:
                    460:     if (metaVerbose) {
                    461:        char *mp;
                    462:
                    463:        /* Describe the target we are building */
1.40      sjg       464:        mp = Var_Subst(NULL, "${" MAKE_META_PREFIX "}", gn, FALSE, TRUE);
1.1       sjg       465:        if (*mp)
                    466:            fprintf(stdout, "%s\n", mp);
                    467:        free(mp);
                    468:     }
                    469:     /* Get the basename of the target */
                    470:     if ((cp = strrchr(tname, '/')) == NULL) {
                    471:        cp = tname;
                    472:     } else {
                    473:        cp++;
                    474:     }
                    475:
                    476:     fflush(stdout);
                    477:
                    478:     if (strcmp(cp, makeDependfile) == 0)
                    479:        goto out;
                    480:
                    481:     if (!writeMeta)
                    482:        /* Don't create meta data. */
                    483:        goto out;
                    484:
                    485:     fname = meta_name(gn, pbm->meta_fname, sizeof(pbm->meta_fname),
                    486:                      dname, tname);
                    487:
1.8       sjg       488: #ifdef DEBUG_META_MODE
                    489:     if (DEBUG(META))
                    490:        fprintf(debug_file, "meta_create: %s\n", fname);
                    491: #endif
                    492:
1.1       sjg       493:     if ((mf.fp = fopen(fname, "w")) == NULL)
                    494:        err(1, "Could not open meta file '%s'", fname);
                    495:
                    496:     fprintf(mf.fp, "# Meta data file %s\n", fname);
                    497:
                    498:     mf.gn = gn;
                    499:
                    500:     Lst_ForEach(gn->commands, printCMD, &mf);
                    501:
                    502:     fprintf(mf.fp, "CWD %s\n", getcwd(buf, sizeof(buf)));
                    503:     fprintf(mf.fp, "TARGET %s\n", tname);
                    504:
                    505:     if (metaEnv) {
                    506:        for (ptr = environ; *ptr != NULL; ptr++)
                    507:            fprintf(mf.fp, "ENV %s\n", *ptr);
                    508:     }
                    509:
                    510:     fprintf(mf.fp, "-- command output --\n");
                    511:     fflush(mf.fp);
                    512:
                    513:     Var_Append(".MAKE.META.FILES", fname, VAR_GLOBAL);
                    514:     Var_Append(".MAKE.META.CREATED", fname, VAR_GLOBAL);
1.22      sjg       515:
                    516:     gn->type |= OP_META;               /* in case anyone wants to know */
                    517:     if (metaSilent) {
                    518:            gn->type |= OP_SILENT;
                    519:     }
1.1       sjg       520:  out:
                    521:     for (i--; i >= 0; i--) {
                    522:        if (p[i])
                    523:            free(p[i]);
                    524:     }
                    525:
                    526:     return (mf.fp);
                    527: }
                    528:
1.12      sjg       529: static Boolean
                    530: boolValue(char *s)
                    531: {
                    532:     switch(*s) {
                    533:     case '0':
                    534:     case 'N':
                    535:     case 'n':
                    536:     case 'F':
                    537:     case 'f':
                    538:        return FALSE;
                    539:     }
                    540:     return TRUE;
                    541: }
1.1       sjg       542:
1.27      sjg       543: /*
                    544:  * Initialization we need before reading makefiles.
                    545:  */
                    546: void
1.30      sjg       547: meta_init(void)
1.27      sjg       548: {
                    549: #ifdef USE_FILEMON
                    550:        /* this allows makefiles to test if we have filemon support */
                    551:        Var_Set(".MAKE.PATH_FILEMON", _PATH_FILEMON, VAR_GLOBAL, 0);
                    552: #endif
                    553: }
                    554:
                    555:
                    556: /*
                    557:  * Initialization we need after reading makefiles.
                    558:  */
1.1       sjg       559: void
1.27      sjg       560: meta_mode_init(const char *make_mode)
1.1       sjg       561: {
                    562:     static int once = 0;
1.12      sjg       563:     char *cp;
1.1       sjg       564:
                    565:     useMeta = TRUE;
                    566:     useFilemon = TRUE;
                    567:     writeMeta = TRUE;
                    568:
                    569:     if (make_mode) {
                    570:        if (strstr(make_mode, "env"))
                    571:            metaEnv = TRUE;
                    572:        if (strstr(make_mode, "verb"))
                    573:            metaVerbose = TRUE;
                    574:        if (strstr(make_mode, "read"))
                    575:            writeMeta = FALSE;
                    576:        if (strstr(make_mode, "nofilemon"))
                    577:            useFilemon = FALSE;
1.13      sjg       578:        if ((cp = strstr(make_mode, "curdirok="))) {
                    579:            metaCurdirOk = boolValue(&cp[9]);
1.12      sjg       580:        }
1.22      sjg       581:        if ((cp = strstr(make_mode, "silent="))) {
                    582:            metaSilent = boolValue(&cp[7]);
                    583:        }
1.1       sjg       584:        if (strstr(make_mode, "ignore-cmd"))
                    585:            metaIgnoreCMDs = TRUE;
                    586:        /* for backwards compatability */
                    587:        Var_Set(".MAKE.META_CREATED", "${.MAKE.META.CREATED}", VAR_GLOBAL, 0);
                    588:        Var_Set(".MAKE.META_FILES", "${.MAKE.META.FILES}", VAR_GLOBAL, 0);
                    589:     }
                    590:     if (metaVerbose && !Var_Exists(MAKE_META_PREFIX, VAR_GLOBAL)) {
                    591:        /*
                    592:         * The default value for MAKE_META_PREFIX
                    593:         * prints the absolute path of the target.
                    594:         * This works be cause :H will generate '.' if there is no /
                    595:         * and :tA will resolve that to cwd.
                    596:         */
                    597:        Var_Set(MAKE_META_PREFIX, "Building ${.TARGET:H:tA}/${.TARGET:T}", VAR_GLOBAL, 0);
                    598:     }
                    599:     if (once)
                    600:        return;
                    601:     once = 1;
                    602:     memset(&Mybm, 0, sizeof(Mybm));
1.17      sjg       603:     /*
                    604:      * We consider ourselves master of all within ${.MAKE.META.BAILIWICK}
                    605:      */
                    606:     metaBailiwick = Lst_Init(FALSE);
1.40      sjg       607:     cp = Var_Subst(NULL, "${.MAKE.META.BAILIWICK:O:u:tA}", VAR_GLOBAL,
                    608:                   FALSE, TRUE);
1.17      sjg       609:     if (cp) {
                    610:        str2Lst_Append(metaBailiwick, cp, NULL);
                    611:     }
1.32      sjg       612:     /*
                    613:      * We ignore any paths that start with ${.MAKE.META.IGNORE_PATHS}
                    614:      */
                    615:     metaIgnorePaths = Lst_Init(FALSE);
                    616:     Var_Append(MAKE_META_IGNORE_PATHS,
                    617:               "/dev /etc /proc /tmp /var/run /var/tmp ${TMPDIR}", VAR_GLOBAL);
                    618:     cp = Var_Subst(NULL,
1.40      sjg       619:                   "${" MAKE_META_IGNORE_PATHS ":O:u:tA}", VAR_GLOBAL,
                    620:                   FALSE, TRUE);
1.32      sjg       621:     if (cp) {
                    622:        str2Lst_Append(metaIgnorePaths, cp, NULL);
                    623:     }
1.1       sjg       624: }
                    625:
                    626: /*
                    627:  * In each case below we allow for job==NULL
                    628:  */
                    629: void
                    630: meta_job_start(Job *job, GNode *gn)
                    631: {
                    632:     BuildMon *pbm;
                    633:
                    634:     if (job != NULL) {
                    635:        pbm = &job->bm;
                    636:     } else {
                    637:        pbm = &Mybm;
                    638:     }
                    639:     pbm->mfp = meta_create(pbm, gn);
                    640: #ifdef USE_FILEMON_ONCE
                    641:     /* compat mode we open the filemon dev once per command */
                    642:     if (job == NULL)
                    643:        return;
                    644: #endif
                    645: #ifdef USE_FILEMON
                    646:     if (pbm->mfp != NULL && useFilemon) {
                    647:        filemon_open(pbm);
                    648:     } else {
                    649:        pbm->mon_fd = pbm->filemon_fd = -1;
                    650:     }
                    651: #endif
                    652: }
                    653:
                    654: /*
                    655:  * The child calls this before doing anything.
                    656:  * It does not disturb our state.
                    657:  */
                    658: void
                    659: meta_job_child(Job *job)
                    660: {
                    661: #ifdef USE_FILEMON
                    662:     BuildMon *pbm;
                    663:
                    664:     if (job != NULL) {
                    665:        pbm = &job->bm;
                    666:     } else {
                    667:        pbm = &Mybm;
                    668:     }
1.37      sjg       669:     if (pbm->mfp != NULL) {
                    670:        close(fileno(pbm->mfp));
                    671:        if (useFilemon) {
                    672:            pid_t pid;
                    673:
                    674:            pid = getpid();
                    675:            if (ioctl(pbm->filemon_fd, FILEMON_SET_PID, &pid) < 0) {
                    676:                err(1, "Could not set filemon pid!");
                    677:            }
1.1       sjg       678:        }
                    679:     }
                    680: #endif
                    681: }
                    682:
                    683: void
                    684: meta_job_error(Job *job, GNode *gn, int flags, int status)
                    685: {
                    686:     char cwd[MAXPATHLEN];
                    687:     BuildMon *pbm;
                    688:
                    689:     if (job != NULL) {
                    690:        pbm = &job->bm;
                    691:     } else {
                    692:        if (!gn)
                    693:            gn = job->node;
                    694:        pbm = &Mybm;
                    695:     }
                    696:     if (pbm->mfp != NULL) {
                    697:        fprintf(pbm->mfp, "*** Error code %d%s\n",
                    698:                status,
                    699:                (flags & JOB_IGNERR) ?
                    700:                "(ignored)" : "");
                    701:     }
                    702:     if (gn) {
                    703:        Var_Set(".ERROR_TARGET", gn->path ? gn->path : gn->name, VAR_GLOBAL, 0);
                    704:     }
                    705:     getcwd(cwd, sizeof(cwd));
                    706:     Var_Set(".ERROR_CWD", cwd, VAR_GLOBAL, 0);
1.6       sjg       707:     if (pbm && pbm->meta_fname[0]) {
1.1       sjg       708:        Var_Set(".ERROR_META_FILE", pbm->meta_fname, VAR_GLOBAL, 0);
                    709:     }
1.16      sjg       710:     meta_job_finish(job);
1.1       sjg       711: }
                    712:
                    713: void
                    714: meta_job_output(Job *job, char *cp, const char *nl)
                    715: {
                    716:     BuildMon *pbm;
                    717:
                    718:     if (job != NULL) {
                    719:        pbm = &job->bm;
                    720:     } else {
                    721:        pbm = &Mybm;
                    722:     }
                    723:     if (pbm->mfp != NULL) {
                    724:        if (metaVerbose) {
                    725:            static char *meta_prefix = NULL;
                    726:            static int meta_prefix_len;
                    727:
                    728:            if (!meta_prefix) {
                    729:                char *cp2;
                    730:
1.40      sjg       731:                meta_prefix = Var_Subst(NULL, "${" MAKE_META_PREFIX "}",
                    732:                                        VAR_GLOBAL, FALSE, TRUE);
1.1       sjg       733:                if ((cp2 = strchr(meta_prefix, '$')))
                    734:                    meta_prefix_len = cp2 - meta_prefix;
                    735:                else
                    736:                    meta_prefix_len = strlen(meta_prefix);
                    737:            }
                    738:            if (strncmp(cp, meta_prefix, meta_prefix_len) == 0) {
                    739:                cp = strchr(cp+1, '\n');
                    740:                if (!cp++)
                    741:                    return;
                    742:            }
                    743:        }
                    744:        fprintf(pbm->mfp, "%s%s", cp, nl);
                    745:     }
                    746: }
                    747:
                    748: void
                    749: meta_cmd_finish(void *pbmp)
                    750: {
                    751: #ifdef USE_FILEMON
                    752:     BuildMon *pbm = pbmp;
                    753:
                    754:     if (!pbm)
                    755:        pbm = &Mybm;
                    756:
                    757:     if (pbm->filemon_fd >= 0) {
                    758:        close(pbm->filemon_fd);
                    759:        filemon_read(pbm->mfp, pbm->mon_fd);
                    760:        pbm->filemon_fd = pbm->mon_fd = -1;
                    761:     }
                    762: #endif
                    763: }
                    764:
                    765: void
                    766: meta_job_finish(Job *job)
                    767: {
                    768:     BuildMon *pbm;
                    769:
                    770:     if (job != NULL) {
                    771:        pbm = &job->bm;
                    772:     } else {
                    773:        pbm = &Mybm;
                    774:     }
                    775:     if (pbm->mfp != NULL) {
                    776:        meta_cmd_finish(pbm);
                    777:        fclose(pbm->mfp);
                    778:        pbm->mfp = NULL;
1.6       sjg       779:        pbm->meta_fname[0] = '\0';
1.1       sjg       780:     }
                    781: }
                    782:
                    783: /*
                    784:  * Fetch a full line from fp - growing bufp if needed
                    785:  * Return length in bufp.
                    786:  */
                    787: static int
                    788: fgetLine(char **bufp, size_t *szp, int o, FILE *fp)
                    789: {
                    790:     char *buf = *bufp;
                    791:     size_t bufsz = *szp;
                    792:     struct stat fs;
                    793:     int x;
                    794:
                    795:     if (fgets(&buf[o], bufsz - o, fp) != NULL) {
                    796:     check_newline:
                    797:        x = o + strlen(&buf[o]);
                    798:        if (buf[x - 1] == '\n')
                    799:            return x;
                    800:        /*
                    801:         * We need to grow the buffer.
                    802:         * The meta file can give us a clue.
                    803:         */
                    804:        if (fstat(fileno(fp), &fs) == 0) {
                    805:            size_t newsz;
                    806:            char *p;
                    807:
                    808:            newsz = ROUNDUP((fs.st_size / 2), BUFSIZ);
                    809:            if (newsz <= bufsz)
                    810:                newsz = ROUNDUP(fs.st_size, BUFSIZ);
                    811:            if (DEBUG(META))
1.19      sjg       812:                fprintf(debug_file, "growing buffer %zu -> %zu\n",
                    813:                        bufsz, newsz);
1.1       sjg       814:            p = bmake_realloc(buf, newsz);
                    815:            if (p) {
                    816:                *bufp = buf = p;
                    817:                *szp = bufsz = newsz;
                    818:                /* fetch the rest */
                    819:                if (!fgets(&buf[x], bufsz - x, fp))
                    820:                    return x;           /* truncated! */
                    821:                goto check_newline;
                    822:            }
                    823:        }
                    824:     }
                    825:     return 0;
                    826: }
                    827:
1.17      sjg       828: static int
                    829: prefix_match(void *p, void *q)
                    830: {
                    831:     const char *prefix = p;
                    832:     const char *path = q;
                    833:     size_t n = strlen(prefix);
                    834:
                    835:     return (0 == strncmp(path, prefix, n));
                    836: }
                    837:
                    838: static int
                    839: string_match(const void *p, const void *q)
                    840: {
                    841:     const char *p1 = p;
                    842:     const char *p2 = q;
                    843:
                    844:     return strcmp(p1, p2);
                    845: }
                    846:
                    847:
1.1       sjg       848: /*
                    849:  * When running with 'meta' functionality, a target can be out-of-date
1.34      snj       850:  * if any of the references in its meta data file is more recent.
1.5       sjg       851:  * We have to track the latestdir on a per-process basis.
1.1       sjg       852:  */
1.38      sjg       853: #define LCWD_VNAME_FMT ".meta.%d.lcwd"
1.5       sjg       854: #define LDIR_VNAME_FMT ".meta.%d.ldir"
                    855:
1.20      sjg       856: /*
                    857:  * It is possible that a .meta file is corrupted,
                    858:  * if we detect this we want to reproduce it.
                    859:  * Setting oodate TRUE will have that effect.
                    860:  */
                    861: #define CHECK_VALID_META(p) if (!(p && *p)) { \
                    862:     warnx("%s: %d: malformed", fname, lineno); \
                    863:     oodate = TRUE; \
                    864:     continue; \
                    865:     }
                    866:
1.33      sjg       867: #define DEQUOTE(p) if (*p == '\'') {   \
                    868:     char *ep; \
                    869:     p++; \
                    870:     if ((ep = strchr(p, '\''))) \
                    871:        *ep = '\0'; \
                    872:     }
                    873:
1.1       sjg       874: Boolean
                    875: meta_oodate(GNode *gn, Boolean oodate)
                    876: {
1.5       sjg       877:     static char *tmpdir = NULL;
1.11      sjg       878:     static char cwd[MAXPATHLEN];
1.38      sjg       879:     char lcwd_vname[64];
1.5       sjg       880:     char ldir_vname[64];
1.38      sjg       881:     char lcwd[MAXPATHLEN];
1.1       sjg       882:     char latestdir[MAXPATHLEN];
                    883:     char fname[MAXPATHLEN];
                    884:     char fname1[MAXPATHLEN];
1.5       sjg       885:     char fname2[MAXPATHLEN];
1.38      sjg       886:     char fname3[MAXPATHLEN];
1.1       sjg       887:     char *p;
                    888:     char *cp;
1.33      sjg       889:     char *link_src;
                    890:     char *move_target;
1.11      sjg       891:     static size_t cwdlen = 0;
1.7       sjg       892:     static size_t tmplen = 0;
1.1       sjg       893:     FILE *fp;
1.26      sjg       894:     Boolean needOODATE = FALSE;
1.17      sjg       895:     Lst missingFiles;
                    896:
1.4       sjg       897:     if (oodate)
                    898:        return oodate;          /* we're done */
                    899:
1.17      sjg       900:     missingFiles = Lst_Init(FALSE);
                    901:
1.1       sjg       902:     /*
                    903:      * We need to check if the target is out-of-date. This includes
                    904:      * checking if the expanded command has changed. This in turn
                    905:      * requires that all variables are set in the same way that they
                    906:      * would be if the target needs to be re-built.
                    907:      */
                    908:     Make_DoAllVar(gn);
                    909:
                    910:     meta_name(gn, fname, sizeof(fname), NULL, NULL);
                    911:
1.8       sjg       912: #ifdef DEBUG_META_MODE
                    913:     if (DEBUG(META))
                    914:        fprintf(debug_file, "meta_oodate: %s\n", fname);
                    915: #endif
                    916:
1.1       sjg       917:     if ((fp = fopen(fname, "r")) != NULL) {
                    918:        static char *buf = NULL;
                    919:        static size_t bufsz;
                    920:        int lineno = 0;
1.5       sjg       921:        int lastpid = 0;
                    922:        int pid;
1.1       sjg       923:        int f = 0;
                    924:        int x;
                    925:        LstNode ln;
                    926:        struct stat fs;
                    927:
                    928:        if (!buf) {
                    929:            bufsz = 8 * BUFSIZ;
                    930:            buf = bmake_malloc(bufsz);
                    931:        }
1.5       sjg       932:
1.11      sjg       933:        if (!cwdlen) {
                    934:            if (getcwd(cwd, sizeof(cwd)) == NULL)
                    935:                err(1, "Could not get current working directory");
                    936:            cwdlen = strlen(cwd);
                    937:        }
1.38      sjg       938:        strlcpy(lcwd, cwd, sizeof(lcwd));
                    939:        strlcpy(latestdir, cwd, sizeof(latestdir));
1.11      sjg       940:
1.5       sjg       941:        if (!tmpdir) {
                    942:            tmpdir = getTmpdir();
                    943:            tmplen = strlen(tmpdir);
                    944:        }
                    945:
1.1       sjg       946:        /* we want to track all the .meta we read */
                    947:        Var_Append(".MAKE.META.FILES", fname, VAR_GLOBAL);
                    948:
                    949:        ln = Lst_First(gn->commands);
                    950:        while (!oodate && (x = fgetLine(&buf, &bufsz, 0, fp)) > 0) {
                    951:            lineno++;
                    952:            if (buf[x - 1] == '\n')
                    953:                buf[x - 1] = '\0';
1.20      sjg       954:            else {
1.1       sjg       955:                warnx("%s: %d: line truncated at %u", fname, lineno, x);
1.20      sjg       956:                oodate = TRUE;
                    957:                break;
                    958:            }
1.33      sjg       959:            link_src = NULL;
                    960:            move_target = NULL;
1.1       sjg       961:            /* Find the start of the build monitor section. */
                    962:            if (!f) {
                    963:                if (strncmp(buf, "-- filemon", 10) == 0) {
                    964:                    f = 1;
                    965:                    continue;
                    966:                }
                    967:                if (strncmp(buf, "# buildmon", 10) == 0) {
                    968:                    f = 1;
                    969:                    continue;
                    970:                }
                    971:            }
                    972:
                    973:            /* Delimit the record type. */
                    974:            p = buf;
1.7       sjg       975: #ifdef DEBUG_META_MODE
                    976:            if (DEBUG(META))
                    977:                fprintf(debug_file, "%s: %d: %s\n", fname, lineno, buf);
                    978: #endif
1.1       sjg       979:            strsep(&p, " ");
                    980:            if (f) {
1.5       sjg       981:                /*
                    982:                 * We are in the 'filemon' output section.
                    983:                 * Each record from filemon follows the general form:
                    984:                 *
                    985:                 * <key> <pid> <data>
                    986:                 *
                    987:                 * Where:
                    988:                 * <key> is a single letter, denoting the syscall.
                    989:                 * <pid> is the process that made the syscall.
                    990:                 * <data> is the arguments (of interest).
                    991:                 */
                    992:                switch(buf[0]) {
                    993:                case '#':               /* comment */
                    994:                case 'V':               /* version */
                    995:                    break;
                    996:                default:
                    997:                    /*
                    998:                     * We need to track pathnames per-process.
                    999:                     *
                   1000:                     * Each process run by make, starts off in the 'CWD'
                   1001:                     * recorded in the .meta file, if it chdirs ('C')
                   1002:                     * elsewhere we need to track that - but only for
                   1003:                     * that process.  If it forks ('F'), we initialize
                   1004:                     * the child to have the same cwd as its parent.
                   1005:                     *
                   1006:                     * We also need to track the 'latestdir' of
                   1007:                     * interest.  This is usually the same as cwd, but
                   1008:                     * not if a process is reading directories.
                   1009:                     *
                   1010:                     * Each time we spot a different process ('pid')
                   1011:                     * we save the current value of 'latestdir' in a
                   1012:                     * variable qualified by 'lastpid', and
                   1013:                     * re-initialize 'latestdir' to any pre-saved
                   1014:                     * value for the current 'pid' and 'CWD' if none.
                   1015:                     */
1.20      sjg      1016:                    CHECK_VALID_META(p);
1.5       sjg      1017:                    pid = atoi(p);
                   1018:                    if (pid > 0 && pid != lastpid) {
                   1019:                        char *ldir;
                   1020:                        char *tp;
                   1021:
                   1022:                        if (lastpid > 0) {
1.38      sjg      1023:                            /* We need to remember these. */
                   1024:                            Var_Set(lcwd_vname, lcwd, VAR_GLOBAL, 0);
1.5       sjg      1025:                            Var_Set(ldir_vname, latestdir, VAR_GLOBAL, 0);
                   1026:                        }
1.38      sjg      1027:                        snprintf(lcwd_vname, sizeof(lcwd_vname), LCWD_VNAME_FMT, pid);
1.5       sjg      1028:                        snprintf(ldir_vname, sizeof(ldir_vname), LDIR_VNAME_FMT, pid);
                   1029:                        lastpid = pid;
                   1030:                        ldir = Var_Value(ldir_vname, VAR_GLOBAL, &tp);
                   1031:                        if (ldir) {
                   1032:                            strlcpy(latestdir, ldir, sizeof(latestdir));
                   1033:                            if (tp)
                   1034:                                free(tp);
1.38      sjg      1035:                        }
                   1036:                        ldir = Var_Value(lcwd_vname, VAR_GLOBAL, &tp);
                   1037:                        if (ldir) {
                   1038:                            strlcpy(lcwd, ldir, sizeof(lcwd));
                   1039:                            if (tp)
                   1040:                                free(tp);
                   1041:                        }
1.5       sjg      1042:                    }
                   1043:                    /* Skip past the pid. */
                   1044:                    if (strsep(&p, " ") == NULL)
                   1045:                        continue;
1.7       sjg      1046: #ifdef DEBUG_META_MODE
                   1047:                    if (DEBUG(META))
1.38      sjg      1048:                            fprintf(debug_file, "%s: %d: %d: %c: cwd=%s lcwd=%s ldir=%s\n",
                   1049:                                    fname, lineno,
                   1050:                                    pid, buf[0], cwd, lcwd, latestdir);
1.7       sjg      1051: #endif
1.5       sjg      1052:                    break;
                   1053:                }
                   1054:
1.20      sjg      1055:                CHECK_VALID_META(p);
                   1056:
1.1       sjg      1057:                /* Process according to record type. */
                   1058:                switch (buf[0]) {
1.5       sjg      1059:                case 'X':               /* eXit */
1.38      sjg      1060:                    Var_Delete(lcwd_vname, VAR_GLOBAL);
1.5       sjg      1061:                    Var_Delete(ldir_vname, VAR_GLOBAL);
                   1062:                    lastpid = 0;        /* no need to save ldir_vname */
                   1063:                    break;
                   1064:
                   1065:                case 'F':               /* [v]Fork */
                   1066:                    {
                   1067:                        char cldir[64];
                   1068:                        int child;
                   1069:
                   1070:                        child = atoi(p);
                   1071:                        if (child > 0) {
1.38      sjg      1072:                            snprintf(cldir, sizeof(cldir), LCWD_VNAME_FMT, child);
                   1073:                            Var_Set(cldir, lcwd, VAR_GLOBAL, 0);
1.5       sjg      1074:                            snprintf(cldir, sizeof(cldir), LDIR_VNAME_FMT, child);
                   1075:                            Var_Set(cldir, latestdir, VAR_GLOBAL, 0);
1.38      sjg      1076: #ifdef DEBUG_META_MODE
                   1077:                            if (DEBUG(META))
                   1078:                                    fprintf(debug_file, "%s: %d: %d: cwd=%s lcwd=%s ldir=%s\n",
                   1079:                                            fname, lineno,
                   1080:                                            child, cwd, lcwd, latestdir);
                   1081: #endif
1.5       sjg      1082:                        }
                   1083:                    }
                   1084:                    break;
1.1       sjg      1085:
1.5       sjg      1086:                case 'C':               /* Chdir */
1.38      sjg      1087:                    /* Update lcwd and latest directory. */
                   1088:                    strlcpy(latestdir, p, sizeof(latestdir));
                   1089:                    strlcpy(lcwd, p, sizeof(lcwd));
                   1090:                    Var_Set(lcwd_vname, lcwd, VAR_GLOBAL, 0);
                   1091:                    Var_Set(ldir_vname, lcwd, VAR_GLOBAL, 0);
                   1092: #ifdef DEBUG_META_MODE
                   1093:                    if (DEBUG(META))
                   1094:                        fprintf(debug_file, "%s: %d: cwd=%s ldir=%s\n", fname, lineno, cwd, lcwd);
                   1095: #endif
1.1       sjg      1096:                    break;
                   1097:
1.17      sjg      1098:                case 'M':               /* renaMe */
1.33      sjg      1099:                    /*
                   1100:                     * For 'M'oves we want to check
                   1101:                     * the src as for 'R'ead
                   1102:                     * and the target as for 'W'rite.
                   1103:                     */
                   1104:                    cp = p;             /* save this for a second */
                   1105:                    /* now get target */
                   1106:                    if (strsep(&p, " ") == NULL)
                   1107:                        continue;
                   1108:                    CHECK_VALID_META(p);
                   1109:                    move_target = p;
                   1110:                    p = cp;
1.17      sjg      1111:                    /* 'L' and 'M' put single quotes around the args */
1.33      sjg      1112:                    DEQUOTE(p);
                   1113:                    DEQUOTE(move_target);
1.17      sjg      1114:                    /* FALLTHROUGH */
                   1115:                case 'D':               /* unlink */
                   1116:                    if (*p == '/' && !Lst_IsEmpty(missingFiles)) {
                   1117:                        /* remove p from the missingFiles list if present */
                   1118:                        if ((ln = Lst_Find(missingFiles, p, string_match)) != NULL) {
                   1119:                            char *tp = Lst_Datum(ln);
                   1120:                            Lst_Remove(missingFiles, ln);
                   1121:                            free(tp);
1.28      sjg      1122:                            ln = NULL;  /* we're done with it */
1.17      sjg      1123:                        }
                   1124:                    }
1.33      sjg      1125:                    if (buf[0] == 'M') {
                   1126:                        /* the target of the mv is a file 'W'ritten */
                   1127: #ifdef DEBUG_META_MODE
                   1128:                        if (DEBUG(META))
                   1129:                            fprintf(debug_file, "meta_oodate: M %s -> %s\n",
                   1130:                                    p, move_target);
                   1131: #endif
                   1132:                        p = move_target;
                   1133:                        goto check_write;
                   1134:                    }
1.17      sjg      1135:                    break;
                   1136:                case 'L':               /* Link */
1.33      sjg      1137:                    /*
                   1138:                     * For 'L'inks check
                   1139:                     * the src as for 'R'ead
                   1140:                     * and the target as for 'W'rite.
                   1141:                     */
                   1142:                    link_src = p;
                   1143:                    /* now get target */
1.17      sjg      1144:                    if (strsep(&p, " ") == NULL)
                   1145:                        continue;
1.20      sjg      1146:                    CHECK_VALID_META(p);
1.17      sjg      1147:                    /* 'L' and 'M' put single quotes around the args */
1.33      sjg      1148:                    DEQUOTE(p);
                   1149:                    DEQUOTE(link_src);
                   1150: #ifdef DEBUG_META_MODE
                   1151:                    if (DEBUG(META))
                   1152:                        fprintf(debug_file, "meta_oodate: L %s -> %s\n",
                   1153:                                link_src, p);
                   1154: #endif
1.17      sjg      1155:                    /* FALLTHROUGH */
                   1156:                case 'W':               /* Write */
1.33      sjg      1157:                check_write:
1.17      sjg      1158:                    /*
                   1159:                     * If a file we generated within our bailiwick
                   1160:                     * but outside of .OBJDIR is missing,
                   1161:                     * we need to do it again.
                   1162:                     */
                   1163:                    /* ignore non-absolute paths */
                   1164:                    if (*p != '/')
                   1165:                        break;
                   1166:
                   1167:                    if (Lst_IsEmpty(metaBailiwick))
                   1168:                        break;
                   1169:
                   1170:                    /* ignore cwd - normal dependencies handle those */
                   1171:                    if (strncmp(p, cwd, cwdlen) == 0)
                   1172:                        break;
                   1173:
                   1174:                    if (!Lst_ForEach(metaBailiwick, prefix_match, p))
                   1175:                        break;
                   1176:
                   1177:                    /* tmpdir might be within */
                   1178:                    if (tmplen > 0 && strncmp(p, tmpdir, tmplen) == 0)
                   1179:                        break;
                   1180:
                   1181:                    /* ignore anything containing the string "tmp" */
                   1182:                    if ((strstr("tmp", p)))
                   1183:                        break;
                   1184:
1.41      sjg      1185:                    if ((link_src != NULL && lstat(p, &fs) < 0) ||
                   1186:                        (link_src == NULL && stat(p, &fs) < 0)) {
1.17      sjg      1187:                        Lst_AtEnd(missingFiles, bmake_strdup(p));
                   1188:                    }
                   1189:                    break;
1.33      sjg      1190:                check_link_src:
                   1191:                    p = link_src;
                   1192:                    link_src = NULL;
                   1193: #ifdef DEBUG_META_MODE
                   1194:                    if (DEBUG(META))
                   1195:                        fprintf(debug_file, "meta_oodate: L src %s\n", p);
                   1196: #endif
                   1197:                    /* FALLTHROUGH */
1.5       sjg      1198:                case 'R':               /* Read */
                   1199:                case 'E':               /* Exec */
1.1       sjg      1200:                    /*
                   1201:                     * Check for runtime files that can't
                   1202:                     * be part of the dependencies because
                   1203:                     * they are _expected_ to change.
                   1204:                     */
1.32      sjg      1205:                    if (*p == '/' &&
                   1206:                        Lst_ForEach(metaIgnorePaths, prefix_match, p)) {
                   1207: #ifdef DEBUG_META_MODE
                   1208:                        if (DEBUG(META))
                   1209:                            fprintf(debug_file, "meta_oodate: ignoring: %s\n",
                   1210:                                    p);
                   1211: #endif
1.31      sjg      1212:                        break;
1.32      sjg      1213:                    }
1.31      sjg      1214:
1.1       sjg      1215:                    /*
1.5       sjg      1216:                     * The rest of the record is the file name.
                   1217:                     * Check if it's not an absolute path.
1.1       sjg      1218:                     */
1.5       sjg      1219:                    {
                   1220:                        char *sdirs[4];
                   1221:                        char **sdp;
                   1222:                        int sdx = 0;
                   1223:                        int found = 0;
                   1224:
                   1225:                        if (*p == '/') {
                   1226:                            sdirs[sdx++] = p; /* done */
                   1227:                        } else {
                   1228:                            if (strcmp(".", p) == 0)
                   1229:                                continue;  /* no point */
                   1230:
                   1231:                            /* Check vs latestdir */
                   1232:                            snprintf(fname1, sizeof(fname1), "%s/%s", latestdir, p);
                   1233:                            sdirs[sdx++] = fname1;
                   1234:
1.38      sjg      1235:                            if (strcmp(latestdir, lcwd) != 0) {
                   1236:                                /* Check vs lcwd */
                   1237:                                snprintf(fname2, sizeof(fname2), "%s/%s", lcwd, p);
                   1238:                                sdirs[sdx++] = fname2;
                   1239:                            }
                   1240:                            if (strcmp(lcwd, cwd) != 0) {
1.5       sjg      1241:                                /* Check vs cwd */
1.38      sjg      1242:                                snprintf(fname3, sizeof(fname3), "%s/%s", cwd, p);
                   1243:                                sdirs[sdx++] = fname3;
1.5       sjg      1244:                            }
                   1245:                        }
                   1246:                        sdirs[sdx++] = NULL;
1.1       sjg      1247:
1.5       sjg      1248:                        for (sdp = sdirs; *sdp && !found; sdp++) {
1.7       sjg      1249: #ifdef DEBUG_META_MODE
                   1250:                            if (DEBUG(META))
                   1251:                                fprintf(debug_file, "%s: %d: looking for: %s\n", fname, lineno, *sdp);
                   1252: #endif
1.5       sjg      1253:                            if (stat(*sdp, &fs) == 0) {
                   1254:                                found = 1;
                   1255:                                p = *sdp;
                   1256:                            }
                   1257:                        }
                   1258:                        if (found) {
1.7       sjg      1259: #ifdef DEBUG_META_MODE
                   1260:                            if (DEBUG(META))
                   1261:                                fprintf(debug_file, "%s: %d: found: %s\n", fname, lineno, p);
                   1262: #endif
1.5       sjg      1263:                            if (!S_ISDIR(fs.st_mode) &&
                   1264:                                fs.st_mtime > gn->mtime) {
                   1265:                                if (DEBUG(META))
                   1266:                                    fprintf(debug_file, "%s: %d: file '%s' is newer than the target...\n", fname, lineno, p);
                   1267:                                oodate = TRUE;
                   1268:                            } else if (S_ISDIR(fs.st_mode)) {
                   1269:                                /* Update the latest directory. */
                   1270:                                realpath(p, latestdir);
                   1271:                            }
                   1272:                        } else if (errno == ENOENT && *p == '/' &&
                   1273:                                   strncmp(p, cwd, cwdlen) != 0) {
                   1274:                            /*
                   1275:                             * A referenced file outside of CWD is missing.
                   1276:                             * We cannot catch every eventuality here...
                   1277:                             */
1.4       sjg      1278:                            if (DEBUG(META))
1.5       sjg      1279:                                fprintf(debug_file, "%s: %d: file '%s' may have moved?...\n", fname, lineno, p);
1.4       sjg      1280:                            oodate = TRUE;
                   1281:                        }
1.1       sjg      1282:                    }
1.38      sjg      1283:                    if (buf[0] == 'E') {
                   1284:                        /* previous latestdir is no longer relevant */
                   1285:                        strlcpy(latestdir, lcwd, sizeof(latestdir));
                   1286:                    }
1.1       sjg      1287:                    break;
                   1288:                default:
                   1289:                    break;
                   1290:                }
1.33      sjg      1291:                if (!oodate && buf[0] == 'L' && link_src != NULL)
                   1292:                    goto check_link_src;
1.5       sjg      1293:            } else if (strcmp(buf, "CMD") == 0) {
1.1       sjg      1294:                /*
                   1295:                 * Compare the current command with the one in the
                   1296:                 * meta data file.
                   1297:                 */
                   1298:                if (ln == NULL) {
                   1299:                    if (DEBUG(META))
                   1300:                        fprintf(debug_file, "%s: %d: there were more build commands in the meta data file than there are now...\n", fname, lineno);
                   1301:                    oodate = TRUE;
                   1302:                } else {
                   1303:                    char *cmd = (char *)Lst_Datum(ln);
1.29      sjg      1304:                    Boolean hasOODATE = FALSE;
1.1       sjg      1305:
1.29      sjg      1306:                    if (strstr(cmd, "$?"))
                   1307:                        hasOODATE = TRUE;
                   1308:                    else if ((cp = strstr(cmd, ".OODATE"))) {
                   1309:                        /* check for $[{(].OODATE[:)}] */
                   1310:                        if (cp > cmd + 2 && cp[-2] == '$')
                   1311:                            hasOODATE = TRUE;
                   1312:                    }
                   1313:                    if (hasOODATE) {
                   1314:                        needOODATE = TRUE;
                   1315:                        if (DEBUG(META))
                   1316:                            fprintf(debug_file, "%s: %d: cannot compare command using .OODATE\n", fname, lineno);
1.1       sjg      1317:                    }
1.40      sjg      1318:                    cmd = Var_Subst(NULL, cmd, gn, TRUE, TRUE);
1.1       sjg      1319:
                   1320:                    if ((cp = strchr(cmd, '\n'))) {
                   1321:                        int n;
                   1322:
                   1323:                        /*
                   1324:                         * This command contains newlines, we need to
                   1325:                         * fetch more from the .meta file before we
                   1326:                         * attempt a comparison.
                   1327:                         */
                   1328:                        /* first put the newline back at buf[x - 1] */
                   1329:                        buf[x - 1] = '\n';
                   1330:                        do {
                   1331:                            /* now fetch the next line */
                   1332:                            if ((n = fgetLine(&buf, &bufsz, x, fp)) <= 0)
                   1333:                                break;
                   1334:                            x = n;
                   1335:                            lineno++;
                   1336:                            if (buf[x - 1] != '\n') {
                   1337:                                warnx("%s: %d: line truncated at %u", fname, lineno, x);
                   1338:                                break;
                   1339:                            }
                   1340:                            cp = strchr(++cp, '\n');
                   1341:                        } while (cp);
                   1342:                        if (buf[x - 1] == '\n')
                   1343:                            buf[x - 1] = '\0';
                   1344:                    }
1.29      sjg      1345:                    if (!hasOODATE &&
1.1       sjg      1346:                        !(gn->type & OP_NOMETA_CMP) &&
                   1347:                        strcmp(p, cmd) != 0) {
                   1348:                        if (DEBUG(META))
                   1349:                            fprintf(debug_file, "%s: %d: a build command has changed\n%s\nvs\n%s\n", fname, lineno, p, cmd);
                   1350:                        if (!metaIgnoreCMDs)
                   1351:                            oodate = TRUE;
                   1352:                    }
                   1353:                    free(cmd);
                   1354:                    ln = Lst_Succ(ln);
                   1355:                }
                   1356:            } else if (strcmp(buf, "CWD") == 0) {
1.14      sjg      1357:                /*
                   1358:                 * Check if there are extra commands now
                   1359:                 * that weren't in the meta data file.
                   1360:                 */
                   1361:                if (!oodate && ln != NULL) {
                   1362:                    if (DEBUG(META))
                   1363:                        fprintf(debug_file, "%s: %d: there are extra build commands now that weren't in the meta data file\n", fname, lineno);
                   1364:                    oodate = TRUE;
                   1365:                }
1.11      sjg      1366:                if (strcmp(p, cwd) != 0) {
1.1       sjg      1367:                    if (DEBUG(META))
                   1368:                        fprintf(debug_file, "%s: %d: the current working directory has changed from '%s' to '%s'\n", fname, lineno, p, curdir);
                   1369:                    oodate = TRUE;
                   1370:                }
                   1371:            }
                   1372:        }
                   1373:
                   1374:        fclose(fp);
1.17      sjg      1375:        if (!Lst_IsEmpty(missingFiles)) {
                   1376:            if (DEBUG(META))
                   1377:                fprintf(debug_file, "%s: missing files: %s...\n",
                   1378:                        fname, (char *)Lst_Datum(Lst_First(missingFiles)));
                   1379:            oodate = TRUE;
                   1380:            Lst_Destroy(missingFiles, (FreeProc *)free);
                   1381:        }
1.21      sjg      1382:     } else {
                   1383:        if ((gn->type & OP_META)) {
                   1384:            if (DEBUG(META))
                   1385:                fprintf(debug_file, "%s: required but missing\n", fname);
                   1386:            oodate = TRUE;
                   1387:        }
1.1       sjg      1388:     }
1.26      sjg      1389:     if (oodate && needOODATE) {
1.4       sjg      1390:        /*
1.26      sjg      1391:         * Target uses .OODATE which is empty; or we wouldn't be here.
                   1392:         * We have decided it is oodate, so .OODATE needs to be set.
                   1393:         * All we can sanely do is set it to .ALLSRC.
1.4       sjg      1394:         */
                   1395:        Var_Delete(OODATE, gn);
1.26      sjg      1396:        Var_Set(OODATE, Var_Value(ALLSRC, gn, &cp), gn, 0);
                   1397:        if (cp)
                   1398:            free(cp);
1.4       sjg      1399:     }
1.1       sjg      1400:     return oodate;
                   1401: }
                   1402:
                   1403: /* support for compat mode */
                   1404:
                   1405: static int childPipe[2];
                   1406:
                   1407: void
                   1408: meta_compat_start(void)
                   1409: {
                   1410: #ifdef USE_FILEMON_ONCE
                   1411:     /*
                   1412:      * We need to re-open filemon for each cmd.
                   1413:      */
                   1414:     BuildMon *pbm = &Mybm;
                   1415:
                   1416:     if (pbm->mfp != NULL && useFilemon) {
                   1417:        filemon_open(pbm);
                   1418:     } else {
                   1419:        pbm->mon_fd = pbm->filemon_fd = -1;
                   1420:     }
                   1421: #endif
                   1422:     if (pipe(childPipe) < 0)
                   1423:        Punt("Cannot create pipe: %s", strerror(errno));
                   1424:     /* Set close-on-exec flag for both */
1.42      christos 1425:     (void)fcntl(childPipe[0], F_SETFD, FD_CLOEXEC);
                   1426:     (void)fcntl(childPipe[1], F_SETFD, FD_CLOEXEC);
1.1       sjg      1427: }
                   1428:
                   1429: void
                   1430: meta_compat_child(void)
                   1431: {
                   1432:     meta_job_child(NULL);
                   1433:     if (dup2(childPipe[1], 1) < 0 ||
                   1434:        dup2(1, 2) < 0) {
                   1435:        execError("dup2", "pipe");
                   1436:        _exit(1);
                   1437:     }
                   1438: }
                   1439:
                   1440: void
                   1441: meta_compat_parent(void)
                   1442: {
                   1443:     FILE *fp;
                   1444:     char buf[BUFSIZ];
                   1445:
                   1446:     close(childPipe[1]);                       /* child side */
                   1447:     fp = fdopen(childPipe[0], "r");
                   1448:     while (fgets(buf, sizeof(buf), fp)) {
                   1449:        meta_job_output(NULL, buf, "");
                   1450:        printf("%s", buf);
                   1451:     }
                   1452:     fclose(fp);
                   1453: }
1.3       sjg      1454:
                   1455: #endif /* USE_META */

CVSweb <webmaster@jp.NetBSD.org>