[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.54

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

CVSweb <webmaster@jp.NetBSD.org>