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

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

CVSweb <webmaster@jp.NetBSD.org>