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

1.115   ! rillig      1: /*      $NetBSD: meta.c,v 1.114 2020/09/12 14:41:00 rillig 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.
1.85      rillig     11:  *
1.1       sjg        12:  * Redistribution and use in source and binary forms, with or without
1.85      rillig     13:  * modification, are permitted provided that the following conditions
                     14:  * are met:
1.1       sjg        15:  * 1. Redistributions of source code must retain the above copyright
1.85      rillig     16:  *    notice, this list of conditions and the following disclaimer.
1.1       sjg        17:  * 2. Redistributions in binary form must reproduce the above copyright
                     18:  *    notice, this list of conditions and the following disclaimer in the
1.85      rillig     19:  *    documentation and/or other materials provided with the distribution.
                     20:  *
1.1       sjg        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
1.85      rillig     31:  * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
1.1       sjg        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 <libgen.h>
                     40: #include <errno.h>
1.2       sjg        41: #if !defined(HAVE_CONFIG_H) || defined(HAVE_ERR_H)
1.1       sjg        42: #include <err.h>
1.2       sjg        43: #endif
1.1       sjg        44:
                     45: #include "make.h"
1.113     rillig     46: #include "dir.h"
1.1       sjg        47: #include "job.h"
                     48:
1.74      riastrad   49: #ifdef USE_FILEMON
1.75      riastrad   50: #include "filemon/filemon.h"
1.73      maxv       51: #endif
                     52:
1.1       sjg        53: static BuildMon Mybm;                  /* for compat */
1.32      sjg        54: static Lst metaBailiwick;              /* our scope of control */
1.53      christos   55: static char *metaBailiwickStr;         /* string storage for the list */
1.32      sjg        56: static Lst metaIgnorePaths;            /* paths we deliberately ignore */
1.53      christos   57: static char *metaIgnorePathsStr;       /* string storage for the list */
1.32      sjg        58:
                     59: #ifndef MAKE_META_IGNORE_PATHS
                     60: #define MAKE_META_IGNORE_PATHS ".MAKE.META.IGNORE_PATHS"
                     61: #endif
1.56      sjg        62: #ifndef MAKE_META_IGNORE_PATTERNS
                     63: #define MAKE_META_IGNORE_PATTERNS ".MAKE.META.IGNORE_PATTERNS"
                     64: #endif
1.66      sjg        65: #ifndef MAKE_META_IGNORE_FILTER
                     66: #define MAKE_META_IGNORE_FILTER ".MAKE.META.IGNORE_FILTER"
                     67: #endif
1.1       sjg        68:
                     69: Boolean useMeta = FALSE;
                     70: static Boolean useFilemon = FALSE;
                     71: static Boolean writeMeta = FALSE;
1.58      sjg        72: static Boolean metaMissing = FALSE;    /* oodate if missing */
                     73: static Boolean filemonMissing = FALSE; /* oodate if missing */
1.1       sjg        74: static Boolean metaEnv = FALSE;                /* don't save env unless asked */
                     75: static Boolean metaVerbose = FALSE;
                     76: static Boolean metaIgnoreCMDs = FALSE; /* ignore CMDs in .meta files */
1.56      sjg        77: static Boolean metaIgnorePatterns = FALSE; /* do we need to do pattern matches */
1.66      sjg        78: static Boolean metaIgnoreFilter = FALSE;   /* do we have more complex filtering? */
1.12      sjg        79: static Boolean metaCurdirOk = FALSE;   /* write .meta in .CURDIR Ok? */
1.22      sjg        80: static Boolean metaSilent = FALSE;     /* if we have a .meta be SILENT */
1.1       sjg        81:
                     82: extern Boolean forceJobs;
                     83: extern Boolean comatMake;
1.25      sjg        84: extern char    **environ;
1.1       sjg        85:
                     86: #define        MAKE_META_PREFIX        ".MAKE.META.PREFIX"
                     87:
                     88: #ifndef N2U
                     89: # define N2U(n, u)   (((n) + ((u) - 1)) / (u))
                     90: #endif
                     91: #ifndef ROUNDUP
                     92: # define ROUNDUP(n, u)   (N2U((n), (u)) * (u))
                     93: #endif
                     94:
1.2       sjg        95: #if !defined(HAVE_STRSEP)
                     96: # define strsep(s, d) stresep((s), (d), 0)
                     97: #endif
                     98:
1.1       sjg        99: /*
1.73      maxv      100:  * Filemon is a kernel module which snoops certain syscalls.
                    101:  *
                    102:  * C chdir
                    103:  * E exec
                    104:  * F [v]fork
                    105:  * L [sym]link
                    106:  * M rename
                    107:  * R read
                    108:  * W write
                    109:  * S stat
                    110:  *
                    111:  * See meta_oodate below - we mainly care about 'E' and 'R'.
                    112:  *
1.85      rillig    113:  * We can still use meta mode without filemon, but
1.73      maxv      114:  * the benefits are more limited.
                    115:  */
                    116: #ifdef USE_FILEMON
                    117:
                    118: /*
                    119:  * Open the filemon device.
                    120:  */
                    121: static void
1.74      riastrad  122: meta_open_filemon(BuildMon *pbm)
1.73      maxv      123: {
1.74      riastrad  124:     int dupfd;
                    125:
                    126:     pbm->mon_fd = -1;
                    127:     pbm->filemon = NULL;
1.77      sjg       128:     if (!useFilemon || !pbm->mfp)
1.73      maxv      129:        return;
                    130:
1.74      riastrad  131:     pbm->filemon = filemon_open();
                    132:     if (pbm->filemon == NULL) {
1.73      maxv      133:        useFilemon = FALSE;
1.75      riastrad  134:        warn("Could not open filemon %s", filemon_path());
1.73      maxv      135:        return;
                    136:     }
                    137:
                    138:     /*
                    139:      * We use a file outside of '.'
                    140:      * to avoid a FreeBSD kernel bug where unlink invalidates
                    141:      * cwd causing getcwd to do a lot more work.
                    142:      * We only care about the descriptor.
                    143:      */
                    144:     pbm->mon_fd = mkTempFile("filemon.XXXXXX", NULL);
1.74      riastrad  145:     if ((dupfd = dup(pbm->mon_fd)) == -1) {
                    146:        err(1, "Could not dup filemon output!");
                    147:     }
                    148:     (void)fcntl(dupfd, F_SETFD, FD_CLOEXEC);
                    149:     if (filemon_setfd(pbm->filemon, dupfd) == -1) {
1.73      maxv      150:        err(1, "Could not set filemon file descriptor!");
                    151:     }
                    152:     /* we don't need these once we exec */
                    153:     (void)fcntl(pbm->mon_fd, F_SETFD, FD_CLOEXEC);
                    154: }
                    155:
                    156: /*
                    157:  * Read the build monitor output file and write records to the target's
                    158:  * metadata file.
                    159:  */
                    160: static int
                    161: filemon_read(FILE *mfp, int fd)
                    162: {
                    163:     char buf[BUFSIZ];
                    164:     int n;
                    165:     int error;
                    166:
                    167:     /* Check if we're not writing to a meta data file.*/
                    168:     if (mfp == NULL) {
                    169:        if (fd >= 0)
                    170:            close(fd);                  /* not interested */
                    171:        return 0;
                    172:     }
                    173:     /* rewind */
1.82      sjg       174:     if (lseek(fd, (off_t)0, SEEK_SET) < 0) {
                    175:        error = errno;
                    176:        warn("Could not rewind filemon");
                    177:        fprintf(mfp, "\n");
                    178:     } else {
                    179:        error = 0;
                    180:        fprintf(mfp, "\n-- filemon acquired metadata --\n");
1.73      maxv      181:
1.82      sjg       182:        while ((n = read(fd, buf, sizeof(buf))) > 0) {
                    183:            if ((int)fwrite(buf, 1, n, mfp) < n)
                    184:                error = EIO;
                    185:        }
1.73      maxv      186:     }
                    187:     fflush(mfp);
                    188:     if (close(fd) < 0)
                    189:        error = errno;
                    190:     return error;
                    191: }
                    192: #endif
                    193:
                    194: /*
1.8       sjg       195:  * when realpath() fails,
                    196:  * we use this, to clean up ./ and ../
                    197:  */
                    198: static void
                    199: eat_dots(char *buf, size_t bufsz, int dots)
                    200: {
                    201:     char *cp;
                    202:     char *cp2;
                    203:     const char *eat;
                    204:     size_t eatlen;
                    205:
                    206:     switch (dots) {
                    207:     case 1:
                    208:        eat = "/./";
                    209:        eatlen = 2;
                    210:        break;
                    211:     case 2:
                    212:        eat = "/../";
                    213:        eatlen = 3;
                    214:        break;
                    215:     default:
                    216:        return;
                    217:     }
1.85      rillig    218:
1.8       sjg       219:     do {
                    220:        cp = strstr(buf, eat);
                    221:        if (cp) {
                    222:            cp2 = cp + eatlen;
                    223:            if (dots == 2 && cp > buf) {
                    224:                do {
                    225:                    cp--;
                    226:                } while (cp > buf && *cp != '/');
                    227:            }
                    228:            if (*cp == '/') {
                    229:                strlcpy(cp, cp2, bufsz - (cp - buf));
                    230:            } else {
                    231:                return;                 /* can't happen? */
                    232:            }
                    233:        }
                    234:     } while (cp);
                    235: }
                    236:
1.1       sjg       237: static char *
                    238: meta_name(struct GNode *gn, char *mname, size_t mnamelen,
                    239:          const char *dname,
1.58      sjg       240:          const char *tname,
                    241:          const char *cwd)
1.1       sjg       242: {
                    243:     char buf[MAXPATHLEN];
                    244:     char *rp;
                    245:     char *cp;
                    246:     char *tp;
1.69      sjg       247:     char *dtp;
                    248:     size_t ldname;
1.8       sjg       249:
1.1       sjg       250:     /*
                    251:      * Weed out relative paths from the target file name.
                    252:      * We have to be careful though since if target is a
                    253:      * symlink, the result will be unstable.
                    254:      * So we use realpath() just to get the dirname, and leave the
                    255:      * basename as given to us.
                    256:      */
                    257:     if ((cp = strrchr(tname, '/'))) {
1.59      sjg       258:        if (cached_realpath(tname, buf)) {
1.1       sjg       259:            if ((rp = strrchr(buf, '/'))) {
                    260:                rp++;
                    261:                cp++;
                    262:                if (strcmp(cp, rp) != 0)
                    263:                    strlcpy(rp, cp, sizeof(buf) - (rp - buf));
                    264:            }
                    265:            tname = buf;
1.8       sjg       266:        } else {
                    267:            /*
                    268:             * We likely have a directory which is about to be made.
                    269:             * We pretend realpath() succeeded, to have a chance
                    270:             * of generating the same meta file name that we will
                    271:             * next time through.
                    272:             */
                    273:            if (tname[0] == '/') {
                    274:                strlcpy(buf, tname, sizeof(buf));
                    275:            } else {
                    276:                snprintf(buf, sizeof(buf), "%s/%s", cwd, tname);
                    277:            }
                    278:            eat_dots(buf, sizeof(buf), 1);      /* ./ */
                    279:            eat_dots(buf, sizeof(buf), 2);      /* ../ */
                    280:            tname = buf;
1.1       sjg       281:        }
                    282:     }
                    283:     /* on some systems dirname may modify its arg */
                    284:     tp = bmake_strdup(tname);
1.69      sjg       285:     dtp = dirname(tp);
                    286:     if (strcmp(dname, dtp) == 0)
1.1       sjg       287:        snprintf(mname, mnamelen, "%s.meta", tname);
                    288:     else {
1.69      sjg       289:        ldname = strlen(dname);
                    290:        if (strncmp(dname, dtp, ldname) == 0 && dtp[ldname] == '/')
                    291:            snprintf(mname, mnamelen, "%s/%s.meta", dname, &tname[ldname+1]);
                    292:        else
                    293:            snprintf(mname, mnamelen, "%s/%s.meta", dname, tname);
1.1       sjg       294:
                    295:        /*
                    296:         * Replace path separators in the file name after the
                    297:         * current object directory path.
                    298:         */
                    299:        cp = mname + strlen(dname) + 1;
                    300:
                    301:        while (*cp != '\0') {
                    302:            if (*cp == '/')
                    303:                *cp = '_';
                    304:            cp++;
                    305:        }
                    306:     }
                    307:     free(tp);
1.84      rillig    308:     return mname;
1.1       sjg       309: }
                    310:
                    311: /*
                    312:  * Return true if running ${.MAKE}
                    313:  * Bypassed if target is flagged .MAKE
                    314:  */
                    315: static int
                    316: is_submake(void *cmdp, void *gnp)
                    317: {
1.90      rillig    318:     static const char *p_make = NULL;
1.1       sjg       319:     static int p_len;
                    320:     char  *cmd = cmdp;
                    321:     GNode *gn = gnp;
                    322:     char *mp = NULL;
                    323:     char *cp;
                    324:     char *cp2;
                    325:     int rc = 0;                                /* keep looking */
                    326:
                    327:     if (!p_make) {
                    328:        p_make = Var_Value(".MAKE", gn, &cp);
                    329:        p_len = strlen(p_make);
                    330:     }
                    331:     cp = strchr(cmd, '$');
                    332:     if ((cp)) {
1.89      rillig    333:        mp = Var_Subst(cmd, gn, VARE_WANTRES);
1.1       sjg       334:        cmd = mp;
                    335:     }
                    336:     cp2 = strstr(cmd, p_make);
                    337:     if ((cp2)) {
                    338:        switch (cp2[p_len]) {
                    339:        case '\0':
                    340:        case ' ':
                    341:        case '\t':
                    342:        case '\n':
                    343:            rc = 1;
                    344:            break;
                    345:        }
                    346:        if (cp2 > cmd && rc > 0) {
                    347:            switch (cp2[-1]) {
                    348:            case ' ':
                    349:            case '\t':
                    350:            case '\n':
                    351:                break;
                    352:            default:
                    353:                rc = 0;                 /* no match */
                    354:                break;
                    355:            }
                    356:        }
                    357:     }
1.44      christos  358:     free(mp);
1.84      rillig    359:     return rc;
1.1       sjg       360: }
                    361:
                    362: typedef struct meta_file_s {
                    363:     FILE *fp;
                    364:     GNode *gn;
                    365: } meta_file_t;
                    366:
                    367: static int
                    368: printCMD(void *cmdp, void *mfpp)
                    369: {
                    370:     meta_file_t *mfp = mfpp;
                    371:     char *cmd = cmdp;
1.111     rillig    372:     char *cmd_freeIt = NULL;
1.1       sjg       373:
                    374:     if (strchr(cmd, '$')) {
1.111     rillig    375:        cmd = cmd_freeIt = Var_Subst(cmd, mfp->gn, VARE_WANTRES);
1.1       sjg       376:     }
                    377:     fprintf(mfp->fp, "CMD %s\n", cmd);
1.111     rillig    378:     free(cmd_freeIt);
1.1       sjg       379:     return 0;
                    380: }
                    381:
                    382: /*
                    383:  * Certain node types never get a .meta file
                    384:  */
                    385: #define SKIP_META_TYPE(_type) do { \
                    386:     if ((gn->type & __CONCAT(OP_, _type))) {   \
1.58      sjg       387:        if (verbose) { \
1.1       sjg       388:            fprintf(debug_file, "Skipping meta for %s: .%s\n", \
                    389:                    gn->name, __STRING(_type));                \
                    390:        } \
1.58      sjg       391:        return FALSE; \
1.1       sjg       392:     } \
                    393: } while (0)
                    394:
1.58      sjg       395:
                    396: /*
                    397:  * Do we need/want a .meta file ?
                    398:  */
                    399: static Boolean
                    400: meta_needed(GNode *gn, const char *dname, const char *tname,
                    401:             char *objdir, int verbose)
1.1       sjg       402: {
1.113     rillig    403:     struct make_stat mst;
1.1       sjg       404:
1.58      sjg       405:     if (verbose)
                    406:        verbose = DEBUG(META);
1.85      rillig    407:
1.1       sjg       408:     /* This may be a phony node which we don't want meta data for... */
                    409:     /* Skip .meta for .BEGIN, .END, .ERROR etc as well. */
                    410:     /* Or it may be explicitly flagged as .NOMETA */
                    411:     SKIP_META_TYPE(NOMETA);
                    412:     /* Unless it is explicitly flagged as .META */
                    413:     if (!(gn->type & OP_META)) {
                    414:        SKIP_META_TYPE(PHONY);
                    415:        SKIP_META_TYPE(SPECIAL);
                    416:        SKIP_META_TYPE(MAKE);
                    417:     }
                    418:
1.58      sjg       419:     /* Check if there are no commands to execute. */
1.106     rillig    420:     if (Lst_IsEmpty(gn->commands)) {
1.58      sjg       421:        if (verbose)
                    422:            fprintf(debug_file, "Skipping meta for %s: no commands\n",
                    423:                    gn->name);
                    424:        return FALSE;
                    425:     }
                    426:     if ((gn->type & (OP_META|OP_SUBMAKE)) == OP_SUBMAKE) {
                    427:        /* OP_SUBMAKE is a bit too aggressive */
1.106     rillig    428:        if (Lst_ForEach(gn->commands, is_submake, gn)) {
1.58      sjg       429:            if (DEBUG(META))
                    430:                fprintf(debug_file, "Skipping meta for %s: .SUBMAKE\n",
                    431:                        gn->name);
                    432:            return FALSE;
                    433:        }
                    434:     }
                    435:
1.1       sjg       436:     /* The object directory may not exist. Check it.. */
1.113     rillig    437:     if (cached_stat(dname, &mst) != 0) {
1.58      sjg       438:        if (verbose)
1.1       sjg       439:            fprintf(debug_file, "Skipping meta for %s: no .OBJDIR\n",
                    440:                    gn->name);
1.58      sjg       441:        return FALSE;
1.1       sjg       442:     }
                    443:
                    444:     /* make sure these are canonical */
1.59      sjg       445:     if (cached_realpath(dname, objdir))
1.1       sjg       446:        dname = objdir;
                    447:
                    448:     /* If we aren't in the object directory, don't create a meta file. */
1.12      sjg       449:     if (!metaCurdirOk && strcmp(curdir, dname) == 0) {
1.58      sjg       450:        if (verbose)
1.1       sjg       451:            fprintf(debug_file, "Skipping meta for %s: .OBJDIR == .CURDIR\n",
                    452:                    gn->name);
1.58      sjg       453:        return FALSE;
                    454:     }
                    455:     return TRUE;
                    456: }
                    457:
1.85      rillig    458:
1.58      sjg       459: static FILE *
                    460: meta_create(BuildMon *pbm, GNode *gn)
                    461: {
                    462:     meta_file_t mf;
                    463:     char buf[MAXPATHLEN];
                    464:     char objdir[MAXPATHLEN];
                    465:     char **ptr;
                    466:     const char *dname;
                    467:     const char *tname;
                    468:     char *fname;
                    469:     const char *cp;
1.76      sjg       470:     char *p[5];                                /* >= possible uses */
1.58      sjg       471:     int i;
                    472:
                    473:     mf.fp = NULL;
                    474:     i = 0;
                    475:
                    476:     dname = Var_Value(".OBJDIR", gn, &p[i++]);
                    477:     tname = Var_Value(TARGET, gn, &p[i++]);
                    478:
                    479:     /* if this succeeds objdir is realpath of dname */
                    480:     if (!meta_needed(gn, dname, tname, objdir, TRUE))
1.1       sjg       481:        goto out;
1.58      sjg       482:     dname = objdir;
1.1       sjg       483:
                    484:     if (metaVerbose) {
                    485:        char *mp;
                    486:
                    487:        /* Describe the target we are building */
1.89      rillig    488:        mp = Var_Subst("${" MAKE_META_PREFIX "}", gn, VARE_WANTRES);
1.1       sjg       489:        if (*mp)
                    490:            fprintf(stdout, "%s\n", mp);
                    491:        free(mp);
                    492:     }
                    493:     /* Get the basename of the target */
                    494:     if ((cp = strrchr(tname, '/')) == NULL) {
                    495:        cp = tname;
                    496:     } else {
                    497:        cp++;
                    498:     }
                    499:
                    500:     fflush(stdout);
                    501:
                    502:     if (!writeMeta)
                    503:        /* Don't create meta data. */
                    504:        goto out;
                    505:
                    506:     fname = meta_name(gn, pbm->meta_fname, sizeof(pbm->meta_fname),
1.58      sjg       507:                      dname, tname, objdir);
1.1       sjg       508:
1.8       sjg       509: #ifdef DEBUG_META_MODE
                    510:     if (DEBUG(META))
                    511:        fprintf(debug_file, "meta_create: %s\n", fname);
                    512: #endif
                    513:
1.1       sjg       514:     if ((mf.fp = fopen(fname, "w")) == NULL)
                    515:        err(1, "Could not open meta file '%s'", fname);
                    516:
                    517:     fprintf(mf.fp, "# Meta data file %s\n", fname);
                    518:
                    519:     mf.gn = gn;
                    520:
1.106     rillig    521:     Lst_ForEach(gn->commands, printCMD, &mf);
1.1       sjg       522:
                    523:     fprintf(mf.fp, "CWD %s\n", getcwd(buf, sizeof(buf)));
                    524:     fprintf(mf.fp, "TARGET %s\n", tname);
1.76      sjg       525:     cp = Var_Value(".OODATE", gn, &p[i++]);
                    526:     if (cp && *cp) {
                    527:            fprintf(mf.fp, "OODATE %s\n", cp);
                    528:     }
1.1       sjg       529:     if (metaEnv) {
                    530:        for (ptr = environ; *ptr != NULL; ptr++)
                    531:            fprintf(mf.fp, "ENV %s\n", *ptr);
                    532:     }
                    533:
                    534:     fprintf(mf.fp, "-- command output --\n");
                    535:     fflush(mf.fp);
                    536:
                    537:     Var_Append(".MAKE.META.FILES", fname, VAR_GLOBAL);
                    538:     Var_Append(".MAKE.META.CREATED", fname, VAR_GLOBAL);
1.22      sjg       539:
                    540:     gn->type |= OP_META;               /* in case anyone wants to know */
                    541:     if (metaSilent) {
                    542:            gn->type |= OP_SILENT;
                    543:     }
1.1       sjg       544:  out:
                    545:     for (i--; i >= 0; i--) {
1.91      rillig    546:        bmake_free(p[i]);
1.1       sjg       547:     }
                    548:
1.84      rillig    549:     return mf.fp;
1.1       sjg       550: }
                    551:
1.12      sjg       552: static Boolean
                    553: boolValue(char *s)
                    554: {
                    555:     switch(*s) {
                    556:     case '0':
                    557:     case 'N':
                    558:     case 'n':
                    559:     case 'F':
                    560:     case 'f':
                    561:        return FALSE;
                    562:     }
                    563:     return TRUE;
                    564: }
1.1       sjg       565:
1.27      sjg       566: /*
                    567:  * Initialization we need before reading makefiles.
                    568:  */
                    569: void
1.30      sjg       570: meta_init(void)
1.27      sjg       571: {
1.73      maxv      572: #ifdef USE_FILEMON
                    573:        /* this allows makefiles to test if we have filemon support */
1.83      rillig    574:        Var_Set(".MAKE.PATH_FILEMON", filemon_path(), VAR_GLOBAL);
1.73      maxv      575: #endif
1.27      sjg       576: }
                    577:
                    578:
1.58      sjg       579: #define get_mode_bf(bf, token) \
                    580:     if ((cp = strstr(make_mode, token))) \
                    581:        bf = boolValue(&cp[sizeof(token) - 1])
                    582:
1.27      sjg       583: /*
                    584:  * Initialization we need after reading makefiles.
                    585:  */
1.1       sjg       586: void
1.27      sjg       587: meta_mode_init(const char *make_mode)
1.1       sjg       588: {
                    589:     static int once = 0;
1.12      sjg       590:     char *cp;
1.1       sjg       591:
                    592:     useMeta = TRUE;
                    593:     useFilemon = TRUE;
                    594:     writeMeta = TRUE;
                    595:
                    596:     if (make_mode) {
                    597:        if (strstr(make_mode, "env"))
                    598:            metaEnv = TRUE;
                    599:        if (strstr(make_mode, "verb"))
                    600:            metaVerbose = TRUE;
                    601:        if (strstr(make_mode, "read"))
                    602:            writeMeta = FALSE;
                    603:        if (strstr(make_mode, "nofilemon"))
                    604:            useFilemon = FALSE;
                    605:        if (strstr(make_mode, "ignore-cmd"))
                    606:            metaIgnoreCMDs = TRUE;
1.58      sjg       607:        if (useFilemon)
                    608:            get_mode_bf(filemonMissing, "missing-filemon=");
                    609:        get_mode_bf(metaCurdirOk, "curdirok=");
                    610:        get_mode_bf(metaMissing, "missing-meta=");
                    611:        get_mode_bf(metaSilent, "silent=");
1.1       sjg       612:     }
                    613:     if (metaVerbose && !Var_Exists(MAKE_META_PREFIX, VAR_GLOBAL)) {
                    614:        /*
                    615:         * The default value for MAKE_META_PREFIX
                    616:         * prints the absolute path of the target.
                    617:         * This works be cause :H will generate '.' if there is no /
                    618:         * and :tA will resolve that to cwd.
                    619:         */
1.83      rillig    620:        Var_Set(MAKE_META_PREFIX, "Building ${.TARGET:H:tA}/${.TARGET:T}", VAR_GLOBAL);
1.1       sjg       621:     }
                    622:     if (once)
                    623:        return;
                    624:     once = 1;
                    625:     memset(&Mybm, 0, sizeof(Mybm));
1.17      sjg       626:     /*
                    627:      * We consider ourselves master of all within ${.MAKE.META.BAILIWICK}
                    628:      */
1.93      rillig    629:     metaBailiwick = Lst_Init();
1.89      rillig    630:     metaBailiwickStr = Var_Subst("${.MAKE.META.BAILIWICK:O:u:tA}",
1.87      rillig    631:        VAR_GLOBAL, VARE_WANTRES);
1.111     rillig    632:     str2Lst_Append(metaBailiwick, metaBailiwickStr, NULL);
1.32      sjg       633:     /*
                    634:      * We ignore any paths that start with ${.MAKE.META.IGNORE_PATHS}
                    635:      */
1.93      rillig    636:     metaIgnorePaths = Lst_Init();
1.32      sjg       637:     Var_Append(MAKE_META_IGNORE_PATHS,
                    638:               "/dev /etc /proc /tmp /var/run /var/tmp ${TMPDIR}", VAR_GLOBAL);
1.89      rillig    639:     metaIgnorePathsStr = Var_Subst("${" MAKE_META_IGNORE_PATHS ":O:u:tA}",
                    640:                                   VAR_GLOBAL, VARE_WANTRES);
1.111     rillig    641:     str2Lst_Append(metaIgnorePaths, metaIgnorePathsStr, NULL);
1.56      sjg       642:
                    643:     /*
                    644:      * We ignore any paths that match ${.MAKE.META.IGNORE_PATTERNS}
                    645:      */
                    646:     cp = NULL;
                    647:     if (Var_Value(MAKE_META_IGNORE_PATTERNS, VAR_GLOBAL, &cp)) {
                    648:        metaIgnorePatterns = TRUE;
1.91      rillig    649:        bmake_free(cp);
1.56      sjg       650:     }
1.66      sjg       651:     cp = NULL;
                    652:     if (Var_Value(MAKE_META_IGNORE_FILTER, VAR_GLOBAL, &cp)) {
                    653:        metaIgnoreFilter = TRUE;
1.91      rillig    654:        bmake_free(cp);
1.66      sjg       655:     }
1.1       sjg       656: }
                    657:
                    658: /*
                    659:  * In each case below we allow for job==NULL
                    660:  */
                    661: void
                    662: meta_job_start(Job *job, GNode *gn)
                    663: {
                    664:     BuildMon *pbm;
                    665:
                    666:     if (job != NULL) {
                    667:        pbm = &job->bm;
                    668:     } else {
                    669:        pbm = &Mybm;
                    670:     }
                    671:     pbm->mfp = meta_create(pbm, gn);
1.73      maxv      672: #ifdef USE_FILEMON_ONCE
                    673:     /* compat mode we open the filemon dev once per command */
                    674:     if (job == NULL)
                    675:        return;
                    676: #endif
                    677: #ifdef USE_FILEMON
                    678:     if (pbm->mfp != NULL && useFilemon) {
1.74      riastrad  679:        meta_open_filemon(pbm);
1.73      maxv      680:     } else {
1.74      riastrad  681:        pbm->mon_fd = -1;
                    682:        pbm->filemon = NULL;
1.73      maxv      683:     }
                    684: #endif
1.1       sjg       685: }
                    686:
                    687: /*
                    688:  * The child calls this before doing anything.
                    689:  * It does not disturb our state.
                    690:  */
                    691: void
                    692: meta_job_child(Job *job)
                    693: {
1.73      maxv      694: #ifdef USE_FILEMON
                    695:     BuildMon *pbm;
                    696:
                    697:     if (job != NULL) {
                    698:        pbm = &job->bm;
                    699:     } else {
                    700:        pbm = &Mybm;
                    701:     }
                    702:     if (pbm->mfp != NULL) {
                    703:        close(fileno(pbm->mfp));
1.77      sjg       704:        if (useFilemon && pbm->filemon) {
1.73      maxv      705:            pid_t pid;
                    706:
                    707:            pid = getpid();
1.74      riastrad  708:            if (filemon_setpid_child(pbm->filemon, pid) == -1) {
1.73      maxv      709:                err(1, "Could not set filemon pid!");
                    710:            }
                    711:        }
                    712:     }
                    713: #endif
1.1       sjg       714: }
                    715:
                    716: void
1.74      riastrad  717: meta_job_parent(Job *job, pid_t pid)
                    718: {
1.78      sjg       719: #if defined(USE_FILEMON) && !defined(USE_FILEMON_DEV)
1.74      riastrad  720:     BuildMon *pbm;
                    721:
                    722:     if (job != NULL) {
                    723:        pbm = &job->bm;
                    724:     } else {
                    725:        pbm = &Mybm;
                    726:     }
1.77      sjg       727:     if (useFilemon && pbm->filemon) {
1.74      riastrad  728:        filemon_setpid_parent(pbm->filemon, pid);
                    729:     }
                    730: #endif
                    731: }
                    732:
                    733: int
                    734: meta_job_fd(Job *job)
                    735: {
1.78      sjg       736: #if defined(USE_FILEMON) && !defined(USE_FILEMON_DEV)
1.74      riastrad  737:     BuildMon *pbm;
                    738:
                    739:     if (job != NULL) {
                    740:        pbm = &job->bm;
                    741:     } else {
                    742:        pbm = &Mybm;
                    743:     }
                    744:     if (useFilemon && pbm->filemon) {
                    745:        return filemon_readfd(pbm->filemon);
                    746:     }
                    747: #endif
                    748:     return -1;
                    749: }
                    750:
                    751: int
                    752: meta_job_event(Job *job)
                    753: {
1.78      sjg       754: #if defined(USE_FILEMON) && !defined(USE_FILEMON_DEV)
1.74      riastrad  755:     BuildMon *pbm;
                    756:
                    757:     if (job != NULL) {
                    758:        pbm = &job->bm;
                    759:     } else {
                    760:        pbm = &Mybm;
                    761:     }
                    762:     if (useFilemon && pbm->filemon) {
                    763:        return filemon_process(pbm->filemon);
                    764:     }
                    765: #endif
                    766:     return 0;
                    767: }
                    768:
                    769: void
1.1       sjg       770: meta_job_error(Job *job, GNode *gn, int flags, int status)
                    771: {
                    772:     char cwd[MAXPATHLEN];
                    773:     BuildMon *pbm;
                    774:
                    775:     if (job != NULL) {
                    776:        pbm = &job->bm;
                    777:        if (!gn)
                    778:            gn = job->node;
1.52      christos  779:     } else {
1.1       sjg       780:        pbm = &Mybm;
                    781:     }
                    782:     if (pbm->mfp != NULL) {
1.68      sjg       783:        fprintf(pbm->mfp, "\n*** Error code %d%s\n",
1.1       sjg       784:                status,
                    785:                (flags & JOB_IGNERR) ?
                    786:                "(ignored)" : "");
                    787:     }
                    788:     if (gn) {
1.83      rillig    789:        Var_Set(".ERROR_TARGET", gn->path ? gn->path : gn->name, VAR_GLOBAL);
1.1       sjg       790:     }
                    791:     getcwd(cwd, sizeof(cwd));
1.83      rillig    792:     Var_Set(".ERROR_CWD", cwd, VAR_GLOBAL);
1.49      christos  793:     if (pbm->meta_fname[0]) {
1.83      rillig    794:        Var_Set(".ERROR_META_FILE", pbm->meta_fname, VAR_GLOBAL);
1.1       sjg       795:     }
1.16      sjg       796:     meta_job_finish(job);
1.1       sjg       797: }
                    798:
                    799: void
                    800: meta_job_output(Job *job, char *cp, const char *nl)
                    801: {
                    802:     BuildMon *pbm;
1.85      rillig    803:
1.1       sjg       804:     if (job != NULL) {
                    805:        pbm = &job->bm;
                    806:     } else {
                    807:        pbm = &Mybm;
                    808:     }
                    809:     if (pbm->mfp != NULL) {
                    810:        if (metaVerbose) {
                    811:            static char *meta_prefix = NULL;
                    812:            static int meta_prefix_len;
                    813:
                    814:            if (!meta_prefix) {
                    815:                char *cp2;
                    816:
1.89      rillig    817:                meta_prefix = Var_Subst("${" MAKE_META_PREFIX "}",
1.87      rillig    818:                                        VAR_GLOBAL, VARE_WANTRES);
1.1       sjg       819:                if ((cp2 = strchr(meta_prefix, '$')))
                    820:                    meta_prefix_len = cp2 - meta_prefix;
                    821:                else
                    822:                    meta_prefix_len = strlen(meta_prefix);
                    823:            }
                    824:            if (strncmp(cp, meta_prefix, meta_prefix_len) == 0) {
                    825:                cp = strchr(cp+1, '\n');
                    826:                if (!cp++)
                    827:                    return;
                    828:            }
                    829:        }
                    830:        fprintf(pbm->mfp, "%s%s", cp, nl);
                    831:     }
                    832: }
                    833:
1.57      sjg       834: int
1.1       sjg       835: meta_cmd_finish(void *pbmp)
                    836: {
1.57      sjg       837:     int error = 0;
1.1       sjg       838:     BuildMon *pbm = pbmp;
1.73      maxv      839: #ifdef USE_FILEMON
                    840:     int x;
                    841: #endif
1.1       sjg       842:
                    843:     if (!pbm)
                    844:        pbm = &Mybm;
                    845:
1.73      maxv      846: #ifdef USE_FILEMON
1.74      riastrad  847:     if (pbm->filemon) {
                    848:        while (filemon_process(pbm->filemon) > 0)
                    849:            continue;
                    850:        if (filemon_close(pbm->filemon) == -1)
1.73      maxv      851:            error = errno;
                    852:        x = filemon_read(pbm->mfp, pbm->mon_fd);
                    853:        if (error == 0 && x != 0)
                    854:            error = x;
1.74      riastrad  855:        pbm->mon_fd = -1;
                    856:        pbm->filemon = NULL;
1.73      maxv      857:     } else
                    858: #endif
                    859:        fprintf(pbm->mfp, "\n");        /* ensure end with newline */
1.57      sjg       860:     return error;
1.1       sjg       861: }
                    862:
1.57      sjg       863: int
1.1       sjg       864: meta_job_finish(Job *job)
                    865: {
                    866:     BuildMon *pbm;
1.57      sjg       867:     int error = 0;
                    868:     int x;
1.1       sjg       869:
                    870:     if (job != NULL) {
                    871:        pbm = &job->bm;
                    872:     } else {
                    873:        pbm = &Mybm;
                    874:     }
                    875:     if (pbm->mfp != NULL) {
1.57      sjg       876:        error = meta_cmd_finish(pbm);
                    877:        x = fclose(pbm->mfp);
                    878:        if (error == 0 && x != 0)
                    879:            error = errno;
1.1       sjg       880:        pbm->mfp = NULL;
1.6       sjg       881:        pbm->meta_fname[0] = '\0';
1.1       sjg       882:     }
1.57      sjg       883:     return error;
1.1       sjg       884: }
                    885:
1.53      christos  886: void
                    887: meta_finish(void)
                    888: {
1.100     rillig    889:     if (metaBailiwick != NULL)
1.106     rillig    890:        Lst_Free(metaBailiwick);
1.53      christos  891:     free(metaBailiwickStr);
1.100     rillig    892:     if (metaIgnorePaths != NULL)
1.106     rillig    893:        Lst_Free(metaIgnorePaths);
1.53      christos  894:     free(metaIgnorePathsStr);
                    895: }
                    896:
1.1       sjg       897: /*
                    898:  * Fetch a full line from fp - growing bufp if needed
                    899:  * Return length in bufp.
                    900:  */
1.85      rillig    901: static int
1.1       sjg       902: fgetLine(char **bufp, size_t *szp, int o, FILE *fp)
                    903: {
                    904:     char *buf = *bufp;
                    905:     size_t bufsz = *szp;
                    906:     struct stat fs;
                    907:     int x;
                    908:
                    909:     if (fgets(&buf[o], bufsz - o, fp) != NULL) {
                    910:     check_newline:
                    911:        x = o + strlen(&buf[o]);
                    912:        if (buf[x - 1] == '\n')
                    913:            return x;
                    914:        /*
                    915:         * We need to grow the buffer.
                    916:         * The meta file can give us a clue.
                    917:         */
                    918:        if (fstat(fileno(fp), &fs) == 0) {
                    919:            size_t newsz;
                    920:            char *p;
                    921:
                    922:            newsz = ROUNDUP((fs.st_size / 2), BUFSIZ);
                    923:            if (newsz <= bufsz)
                    924:                newsz = ROUNDUP(fs.st_size, BUFSIZ);
1.68      sjg       925:            if (newsz <= bufsz)
                    926:                return x;               /* truncated */
1.85      rillig    927:            if (DEBUG(META))
1.19      sjg       928:                fprintf(debug_file, "growing buffer %zu -> %zu\n",
                    929:                        bufsz, newsz);
1.1       sjg       930:            p = bmake_realloc(buf, newsz);
                    931:            if (p) {
                    932:                *bufp = buf = p;
                    933:                *szp = bufsz = newsz;
                    934:                /* fetch the rest */
                    935:                if (!fgets(&buf[x], bufsz - x, fp))
                    936:                    return x;           /* truncated! */
                    937:                goto check_newline;
                    938:            }
                    939:        }
                    940:     }
                    941:     return 0;
                    942: }
                    943:
1.64      sjg       944: /* Lst_ForEach wants 1 to stop search */
1.17      sjg       945: static int
                    946: prefix_match(void *p, void *q)
                    947: {
                    948:     const char *prefix = p;
                    949:     const char *path = q;
                    950:     size_t n = strlen(prefix);
                    951:
1.84      rillig    952:     return strncmp(path, prefix, n) == 0;
1.17      sjg       953: }
                    954:
1.108     rillig    955: /* See if the path equals prefix or starts with "prefix/". */
                    956: static Boolean
1.64      sjg       957: path_match(const void *p, const void *q)
                    958: {
1.108     rillig    959:     const char *path = p;
1.64      sjg       960:     const char *prefix = q;
                    961:     size_t n = strlen(prefix);
                    962:
1.108     rillig    963:     if (strncmp(path, prefix, n) != 0)
1.114     rillig    964:        return FALSE;
1.108     rillig    965:     return path[n] == '\0' || path[n] == '/';
1.64      sjg       966: }
                    967:
1.108     rillig    968: static Boolean
1.17      sjg       969: string_match(const void *p, const void *q)
                    970: {
1.108     rillig    971:     return strcmp(p, q) == 0;
1.17      sjg       972: }
                    973:
                    974:
1.67      sjg       975: static int
                    976: meta_ignore(GNode *gn, const char *p)
                    977: {
                    978:     char fname[MAXPATHLEN];
                    979:
                    980:     if (p == NULL)
                    981:        return TRUE;
                    982:
                    983:     if (*p == '/') {
                    984:        cached_realpath(p, fname); /* clean it up */
1.106     rillig    985:        if (Lst_ForEach(metaIgnorePaths, prefix_match, fname)) {
1.67      sjg       986: #ifdef DEBUG_META_MODE
                    987:            if (DEBUG(META))
                    988:                fprintf(debug_file, "meta_oodate: ignoring path: %s\n",
                    989:                        p);
                    990: #endif
                    991:            return TRUE;
                    992:        }
                    993:     }
                    994:
                    995:     if (metaIgnorePatterns) {
1.97      rillig    996:        const char *expr;
                    997:        char *pm;
1.92      rillig    998:
1.83      rillig    999:        Var_Set(".p.", p, gn);
1.92      rillig   1000:        expr = "${" MAKE_META_IGNORE_PATTERNS ":@m@${.p.:M$m}@}";
                   1001:        pm = Var_Subst(expr, gn, VARE_WANTRES);
1.67      sjg      1002:        if (*pm) {
                   1003: #ifdef DEBUG_META_MODE
                   1004:            if (DEBUG(META))
                   1005:                fprintf(debug_file, "meta_oodate: ignoring pattern: %s\n",
                   1006:                        p);
                   1007: #endif
                   1008:            free(pm);
                   1009:            return TRUE;
                   1010:        }
                   1011:        free(pm);
                   1012:     }
                   1013:
                   1014:     if (metaIgnoreFilter) {
                   1015:        char *fm;
                   1016:
                   1017:        /* skip if filter result is empty */
                   1018:        snprintf(fname, sizeof(fname),
                   1019:                 "${%s:L:${%s:ts:}}",
                   1020:                 p, MAKE_META_IGNORE_FILTER);
1.89      rillig   1021:        fm = Var_Subst(fname, gn, VARE_WANTRES);
1.67      sjg      1022:        if (*fm == '\0') {
                   1023: #ifdef DEBUG_META_MODE
                   1024:            if (DEBUG(META))
                   1025:                fprintf(debug_file, "meta_oodate: ignoring filtered: %s\n",
                   1026:                        p);
                   1027: #endif
                   1028:            free(fm);
                   1029:            return TRUE;
                   1030:        }
                   1031:        free(fm);
                   1032:     }
                   1033:     return FALSE;
                   1034: }
                   1035:
1.1       sjg      1036: /*
                   1037:  * When running with 'meta' functionality, a target can be out-of-date
1.34      snj      1038:  * if any of the references in its meta data file is more recent.
1.5       sjg      1039:  * We have to track the latestdir on a per-process basis.
1.1       sjg      1040:  */
1.38      sjg      1041: #define LCWD_VNAME_FMT ".meta.%d.lcwd"
1.5       sjg      1042: #define LDIR_VNAME_FMT ".meta.%d.ldir"
                   1043:
1.20      sjg      1044: /*
                   1045:  * It is possible that a .meta file is corrupted,
                   1046:  * if we detect this we want to reproduce it.
                   1047:  * Setting oodate TRUE will have that effect.
                   1048:  */
                   1049: #define CHECK_VALID_META(p) if (!(p && *p)) { \
                   1050:     warnx("%s: %d: malformed", fname, lineno); \
                   1051:     oodate = TRUE; \
                   1052:     continue; \
                   1053:     }
                   1054:
1.33      sjg      1055: #define DEQUOTE(p) if (*p == '\'') {   \
                   1056:     char *ep; \
                   1057:     p++; \
                   1058:     if ((ep = strchr(p, '\''))) \
                   1059:        *ep = '\0'; \
                   1060:     }
                   1061:
1.1       sjg      1062: Boolean
                   1063: meta_oodate(GNode *gn, Boolean oodate)
                   1064: {
1.5       sjg      1065:     static char *tmpdir = NULL;
1.11      sjg      1066:     static char cwd[MAXPATHLEN];
1.38      sjg      1067:     char lcwd_vname[64];
1.5       sjg      1068:     char ldir_vname[64];
1.38      sjg      1069:     char lcwd[MAXPATHLEN];
1.1       sjg      1070:     char latestdir[MAXPATHLEN];
                   1071:     char fname[MAXPATHLEN];
                   1072:     char fname1[MAXPATHLEN];
1.5       sjg      1073:     char fname2[MAXPATHLEN];
1.38      sjg      1074:     char fname3[MAXPATHLEN];
1.58      sjg      1075:     const char *dname;
                   1076:     const char *tname;
1.1       sjg      1077:     char *p;
                   1078:     char *cp;
1.33      sjg      1079:     char *link_src;
                   1080:     char *move_target;
1.11      sjg      1081:     static size_t cwdlen = 0;
1.7       sjg      1082:     static size_t tmplen = 0;
1.1       sjg      1083:     FILE *fp;
1.26      sjg      1084:     Boolean needOODATE = FALSE;
1.17      sjg      1085:     Lst missingFiles;
1.58      sjg      1086:     char *pa[4];                       /* >= possible uses */
                   1087:     int i;
                   1088:     int have_filemon = FALSE;
                   1089:
1.4       sjg      1090:     if (oodate)
                   1091:        return oodate;          /* we're done */
                   1092:
1.58      sjg      1093:     i = 0;
                   1094:
                   1095:     dname = Var_Value(".OBJDIR", gn, &pa[i++]);
                   1096:     tname = Var_Value(TARGET, gn, &pa[i++]);
                   1097:
                   1098:     /* if this succeeds fname3 is realpath of dname */
                   1099:     if (!meta_needed(gn, dname, tname, fname3, FALSE))
                   1100:        goto oodate_out;
                   1101:     dname = fname3;
                   1102:
1.93      rillig   1103:     missingFiles = Lst_Init();
1.17      sjg      1104:
1.1       sjg      1105:     /*
                   1106:      * We need to check if the target is out-of-date. This includes
                   1107:      * checking if the expanded command has changed. This in turn
                   1108:      * requires that all variables are set in the same way that they
                   1109:      * would be if the target needs to be re-built.
                   1110:      */
                   1111:     Make_DoAllVar(gn);
                   1112:
1.58      sjg      1113:     meta_name(gn, fname, sizeof(fname), dname, tname, dname);
1.1       sjg      1114:
1.8       sjg      1115: #ifdef DEBUG_META_MODE
                   1116:     if (DEBUG(META))
                   1117:        fprintf(debug_file, "meta_oodate: %s\n", fname);
                   1118: #endif
                   1119:
1.1       sjg      1120:     if ((fp = fopen(fname, "r")) != NULL) {
                   1121:        static char *buf = NULL;
                   1122:        static size_t bufsz;
                   1123:        int lineno = 0;
1.5       sjg      1124:        int lastpid = 0;
                   1125:        int pid;
1.1       sjg      1126:        int x;
1.115   ! rillig   1127:        StringListNode *cmdNode;
1.113     rillig   1128:        struct make_stat mst;
1.1       sjg      1129:
                   1130:        if (!buf) {
                   1131:            bufsz = 8 * BUFSIZ;
                   1132:            buf = bmake_malloc(bufsz);
                   1133:        }
1.5       sjg      1134:
1.11      sjg      1135:        if (!cwdlen) {
                   1136:            if (getcwd(cwd, sizeof(cwd)) == NULL)
                   1137:                err(1, "Could not get current working directory");
                   1138:            cwdlen = strlen(cwd);
                   1139:        }
1.38      sjg      1140:        strlcpy(lcwd, cwd, sizeof(lcwd));
                   1141:        strlcpy(latestdir, cwd, sizeof(latestdir));
1.11      sjg      1142:
1.5       sjg      1143:        if (!tmpdir) {
                   1144:            tmpdir = getTmpdir();
                   1145:            tmplen = strlen(tmpdir);
                   1146:        }
                   1147:
1.1       sjg      1148:        /* we want to track all the .meta we read */
                   1149:        Var_Append(".MAKE.META.FILES", fname, VAR_GLOBAL);
                   1150:
1.115   ! rillig   1151:        cmdNode = Lst_First(gn->commands);
1.1       sjg      1152:        while (!oodate && (x = fgetLine(&buf, &bufsz, 0, fp)) > 0) {
                   1153:            lineno++;
                   1154:            if (buf[x - 1] == '\n')
                   1155:                buf[x - 1] = '\0';
1.20      sjg      1156:            else {
1.1       sjg      1157:                warnx("%s: %d: line truncated at %u", fname, lineno, x);
1.20      sjg      1158:                oodate = TRUE;
                   1159:                break;
                   1160:            }
1.33      sjg      1161:            link_src = NULL;
                   1162:            move_target = NULL;
1.1       sjg      1163:            /* Find the start of the build monitor section. */
1.58      sjg      1164:            if (!have_filemon) {
1.1       sjg      1165:                if (strncmp(buf, "-- filemon", 10) == 0) {
1.58      sjg      1166:                    have_filemon = TRUE;
1.1       sjg      1167:                    continue;
                   1168:                }
                   1169:                if (strncmp(buf, "# buildmon", 10) == 0) {
1.58      sjg      1170:                    have_filemon = TRUE;
1.1       sjg      1171:                    continue;
                   1172:                }
1.85      rillig   1173:            }
1.1       sjg      1174:
                   1175:            /* Delimit the record type. */
                   1176:            p = buf;
1.7       sjg      1177: #ifdef DEBUG_META_MODE
                   1178:            if (DEBUG(META))
                   1179:                fprintf(debug_file, "%s: %d: %s\n", fname, lineno, buf);
                   1180: #endif
1.1       sjg      1181:            strsep(&p, " ");
1.58      sjg      1182:            if (have_filemon) {
1.5       sjg      1183:                /*
                   1184:                 * We are in the 'filemon' output section.
                   1185:                 * Each record from filemon follows the general form:
                   1186:                 *
                   1187:                 * <key> <pid> <data>
                   1188:                 *
                   1189:                 * Where:
                   1190:                 * <key> is a single letter, denoting the syscall.
                   1191:                 * <pid> is the process that made the syscall.
                   1192:                 * <data> is the arguments (of interest).
                   1193:                 */
                   1194:                switch(buf[0]) {
                   1195:                case '#':               /* comment */
                   1196:                case 'V':               /* version */
                   1197:                    break;
                   1198:                default:
                   1199:                    /*
                   1200:                     * We need to track pathnames per-process.
                   1201:                     *
                   1202:                     * Each process run by make, starts off in the 'CWD'
                   1203:                     * recorded in the .meta file, if it chdirs ('C')
                   1204:                     * elsewhere we need to track that - but only for
                   1205:                     * that process.  If it forks ('F'), we initialize
                   1206:                     * the child to have the same cwd as its parent.
                   1207:                     *
                   1208:                     * We also need to track the 'latestdir' of
                   1209:                     * interest.  This is usually the same as cwd, but
                   1210:                     * not if a process is reading directories.
                   1211:                     *
                   1212:                     * Each time we spot a different process ('pid')
                   1213:                     * we save the current value of 'latestdir' in a
                   1214:                     * variable qualified by 'lastpid', and
                   1215:                     * re-initialize 'latestdir' to any pre-saved
                   1216:                     * value for the current 'pid' and 'CWD' if none.
                   1217:                     */
1.20      sjg      1218:                    CHECK_VALID_META(p);
1.5       sjg      1219:                    pid = atoi(p);
                   1220:                    if (pid > 0 && pid != lastpid) {
1.90      rillig   1221:                        const char *ldir;
1.5       sjg      1222:                        char *tp;
1.83      rillig   1223:
1.5       sjg      1224:                        if (lastpid > 0) {
1.38      sjg      1225:                            /* We need to remember these. */
1.83      rillig   1226:                            Var_Set(lcwd_vname, lcwd, VAR_GLOBAL);
                   1227:                            Var_Set(ldir_vname, latestdir, VAR_GLOBAL);
1.5       sjg      1228:                        }
1.38      sjg      1229:                        snprintf(lcwd_vname, sizeof(lcwd_vname), LCWD_VNAME_FMT, pid);
1.5       sjg      1230:                        snprintf(ldir_vname, sizeof(ldir_vname), LDIR_VNAME_FMT, pid);
                   1231:                        lastpid = pid;
                   1232:                        ldir = Var_Value(ldir_vname, VAR_GLOBAL, &tp);
                   1233:                        if (ldir) {
                   1234:                            strlcpy(latestdir, ldir, sizeof(latestdir));
1.91      rillig   1235:                            bmake_free(tp);
1.38      sjg      1236:                        }
                   1237:                        ldir = Var_Value(lcwd_vname, VAR_GLOBAL, &tp);
                   1238:                        if (ldir) {
                   1239:                            strlcpy(lcwd, ldir, sizeof(lcwd));
1.91      rillig   1240:                            bmake_free(tp);
1.38      sjg      1241:                        }
1.5       sjg      1242:                    }
                   1243:                    /* Skip past the pid. */
                   1244:                    if (strsep(&p, " ") == NULL)
                   1245:                        continue;
1.7       sjg      1246: #ifdef DEBUG_META_MODE
                   1247:                    if (DEBUG(META))
1.38      sjg      1248:                            fprintf(debug_file, "%s: %d: %d: %c: cwd=%s lcwd=%s ldir=%s\n",
                   1249:                                    fname, lineno,
                   1250:                                    pid, buf[0], cwd, lcwd, latestdir);
1.7       sjg      1251: #endif
1.5       sjg      1252:                    break;
                   1253:                }
                   1254:
1.20      sjg      1255:                CHECK_VALID_META(p);
                   1256:
1.1       sjg      1257:                /* Process according to record type. */
                   1258:                switch (buf[0]) {
1.5       sjg      1259:                case 'X':               /* eXit */
1.38      sjg      1260:                    Var_Delete(lcwd_vname, VAR_GLOBAL);
1.5       sjg      1261:                    Var_Delete(ldir_vname, VAR_GLOBAL);
                   1262:                    lastpid = 0;        /* no need to save ldir_vname */
                   1263:                    break;
                   1264:
                   1265:                case 'F':               /* [v]Fork */
                   1266:                    {
                   1267:                        char cldir[64];
                   1268:                        int child;
                   1269:
                   1270:                        child = atoi(p);
                   1271:                        if (child > 0) {
1.38      sjg      1272:                            snprintf(cldir, sizeof(cldir), LCWD_VNAME_FMT, child);
1.83      rillig   1273:                            Var_Set(cldir, lcwd, VAR_GLOBAL);
1.5       sjg      1274:                            snprintf(cldir, sizeof(cldir), LDIR_VNAME_FMT, child);
1.83      rillig   1275:                            Var_Set(cldir, latestdir, VAR_GLOBAL);
1.38      sjg      1276: #ifdef DEBUG_META_MODE
                   1277:                            if (DEBUG(META))
                   1278:                                    fprintf(debug_file, "%s: %d: %d: cwd=%s lcwd=%s ldir=%s\n",
                   1279:                                            fname, lineno,
                   1280:                                            child, cwd, lcwd, latestdir);
                   1281: #endif
1.5       sjg      1282:                        }
                   1283:                    }
                   1284:                    break;
1.1       sjg      1285:
1.5       sjg      1286:                case 'C':               /* Chdir */
1.38      sjg      1287:                    /* Update lcwd and latest directory. */
1.85      rillig   1288:                    strlcpy(latestdir, p, sizeof(latestdir));
1.38      sjg      1289:                    strlcpy(lcwd, p, sizeof(lcwd));
1.83      rillig   1290:                    Var_Set(lcwd_vname, lcwd, VAR_GLOBAL);
                   1291:                    Var_Set(ldir_vname, lcwd, VAR_GLOBAL);
1.38      sjg      1292: #ifdef DEBUG_META_MODE
                   1293:                    if (DEBUG(META))
                   1294:                        fprintf(debug_file, "%s: %d: cwd=%s ldir=%s\n", fname, lineno, cwd, lcwd);
                   1295: #endif
1.1       sjg      1296:                    break;
                   1297:
1.17      sjg      1298:                case 'M':               /* renaMe */
1.33      sjg      1299:                    /*
                   1300:                     * For 'M'oves we want to check
                   1301:                     * the src as for 'R'ead
                   1302:                     * and the target as for 'W'rite.
                   1303:                     */
                   1304:                    cp = p;             /* save this for a second */
                   1305:                    /* now get target */
                   1306:                    if (strsep(&p, " ") == NULL)
                   1307:                        continue;
                   1308:                    CHECK_VALID_META(p);
                   1309:                    move_target = p;
                   1310:                    p = cp;
1.17      sjg      1311:                    /* 'L' and 'M' put single quotes around the args */
1.33      sjg      1312:                    DEQUOTE(p);
                   1313:                    DEQUOTE(move_target);
1.17      sjg      1314:                    /* FALLTHROUGH */
                   1315:                case 'D':               /* unlink */
1.106     rillig   1316:                    if (*p == '/' && !Lst_IsEmpty(missingFiles)) {
1.64      sjg      1317:                        /* remove any missingFiles entries that match p */
1.115   ! rillig   1318:                        StringListNode *missingNode =
        !          1319:                                Lst_Find(missingFiles, path_match, p);
        !          1320:                        if (missingNode != NULL) {
        !          1321:                            StringListNode *nln;
1.64      sjg      1322:
                   1323:                            do {
1.115   ! rillig   1324:                                char *tp;
1.110     rillig   1325:                                nln = Lst_FindFrom(missingFiles,
1.115   ! rillig   1326:                                                   LstNode_Next(missingNode),
1.110     rillig   1327:                                                   path_match, p);
1.115   ! rillig   1328:                                tp = LstNode_Datum(missingNode);
        !          1329:                                Lst_Remove(missingFiles, missingNode);
1.64      sjg      1330:                                free(tp);
1.115   ! rillig   1331:                            } while ((missingNode = nln) != NULL);
1.17      sjg      1332:                        }
                   1333:                    }
1.33      sjg      1334:                    if (buf[0] == 'M') {
                   1335:                        /* the target of the mv is a file 'W'ritten */
                   1336: #ifdef DEBUG_META_MODE
                   1337:                        if (DEBUG(META))
                   1338:                            fprintf(debug_file, "meta_oodate: M %s -> %s\n",
                   1339:                                    p, move_target);
                   1340: #endif
                   1341:                        p = move_target;
                   1342:                        goto check_write;
                   1343:                    }
1.17      sjg      1344:                    break;
                   1345:                case 'L':               /* Link */
1.33      sjg      1346:                    /*
                   1347:                     * For 'L'inks check
                   1348:                     * the src as for 'R'ead
                   1349:                     * and the target as for 'W'rite.
                   1350:                     */
                   1351:                    link_src = p;
                   1352:                    /* now get target */
1.17      sjg      1353:                    if (strsep(&p, " ") == NULL)
                   1354:                        continue;
1.20      sjg      1355:                    CHECK_VALID_META(p);
1.17      sjg      1356:                    /* 'L' and 'M' put single quotes around the args */
1.33      sjg      1357:                    DEQUOTE(p);
                   1358:                    DEQUOTE(link_src);
                   1359: #ifdef DEBUG_META_MODE
                   1360:                    if (DEBUG(META))
                   1361:                        fprintf(debug_file, "meta_oodate: L %s -> %s\n",
                   1362:                                link_src, p);
                   1363: #endif
1.17      sjg      1364:                    /* FALLTHROUGH */
                   1365:                case 'W':               /* Write */
1.33      sjg      1366:                check_write:
1.17      sjg      1367:                    /*
                   1368:                     * If a file we generated within our bailiwick
                   1369:                     * but outside of .OBJDIR is missing,
1.85      rillig   1370:                     * we need to do it again.
1.17      sjg      1371:                     */
                   1372:                    /* ignore non-absolute paths */
                   1373:                    if (*p != '/')
                   1374:                        break;
                   1375:
1.106     rillig   1376:                    if (Lst_IsEmpty(metaBailiwick))
1.17      sjg      1377:                        break;
                   1378:
                   1379:                    /* ignore cwd - normal dependencies handle those */
                   1380:                    if (strncmp(p, cwd, cwdlen) == 0)
                   1381:                        break;
                   1382:
1.106     rillig   1383:                    if (!Lst_ForEach(metaBailiwick, prefix_match, p))
1.17      sjg      1384:                        break;
                   1385:
                   1386:                    /* tmpdir might be within */
                   1387:                    if (tmplen > 0 && strncmp(p, tmpdir, tmplen) == 0)
                   1388:                        break;
                   1389:
                   1390:                    /* ignore anything containing the string "tmp" */
                   1391:                    if ((strstr("tmp", p)))
                   1392:                        break;
                   1393:
1.113     rillig   1394:                    if ((link_src != NULL && cached_lstat(p, &mst) < 0) ||
                   1395:                        (link_src == NULL && cached_stat(p, &mst) < 0)) {
1.67      sjg      1396:                        if (!meta_ignore(gn, p)) {
1.109     rillig   1397:                            if (Lst_Find(missingFiles, string_match, p) == NULL)
1.106     rillig   1398:                                Lst_Append(missingFiles, bmake_strdup(p));
1.67      sjg      1399:                        }
1.17      sjg      1400:                    }
                   1401:                    break;
1.33      sjg      1402:                check_link_src:
                   1403:                    p = link_src;
                   1404:                    link_src = NULL;
                   1405: #ifdef DEBUG_META_MODE
                   1406:                    if (DEBUG(META))
                   1407:                        fprintf(debug_file, "meta_oodate: L src %s\n", p);
                   1408: #endif
                   1409:                    /* FALLTHROUGH */
1.5       sjg      1410:                case 'R':               /* Read */
                   1411:                case 'E':               /* Exec */
1.1       sjg      1412:                    /*
                   1413:                     * Check for runtime files that can't
                   1414:                     * be part of the dependencies because
                   1415:                     * they are _expected_ to change.
                   1416:                     */
1.67      sjg      1417:                    if (meta_ignore(gn, p))
                   1418:                        break;
1.85      rillig   1419:
1.1       sjg      1420:                    /*
1.5       sjg      1421:                     * The rest of the record is the file name.
                   1422:                     * Check if it's not an absolute path.
1.1       sjg      1423:                     */
1.5       sjg      1424:                    {
                   1425:                        char *sdirs[4];
                   1426:                        char **sdp;
                   1427:                        int sdx = 0;
                   1428:                        int found = 0;
                   1429:
                   1430:                        if (*p == '/') {
                   1431:                            sdirs[sdx++] = p; /* done */
                   1432:                        } else {
                   1433:                            if (strcmp(".", p) == 0)
                   1434:                                continue;  /* no point */
                   1435:
                   1436:                            /* Check vs latestdir */
                   1437:                            snprintf(fname1, sizeof(fname1), "%s/%s", latestdir, p);
                   1438:                            sdirs[sdx++] = fname1;
                   1439:
1.38      sjg      1440:                            if (strcmp(latestdir, lcwd) != 0) {
                   1441:                                /* Check vs lcwd */
                   1442:                                snprintf(fname2, sizeof(fname2), "%s/%s", lcwd, p);
                   1443:                                sdirs[sdx++] = fname2;
                   1444:                            }
                   1445:                            if (strcmp(lcwd, cwd) != 0) {
1.5       sjg      1446:                                /* Check vs cwd */
1.38      sjg      1447:                                snprintf(fname3, sizeof(fname3), "%s/%s", cwd, p);
                   1448:                                sdirs[sdx++] = fname3;
1.5       sjg      1449:                            }
                   1450:                        }
                   1451:                        sdirs[sdx++] = NULL;
1.1       sjg      1452:
1.5       sjg      1453:                        for (sdp = sdirs; *sdp && !found; sdp++) {
1.7       sjg      1454: #ifdef DEBUG_META_MODE
                   1455:                            if (DEBUG(META))
                   1456:                                fprintf(debug_file, "%s: %d: looking for: %s\n", fname, lineno, *sdp);
                   1457: #endif
1.113     rillig   1458:                            if (cached_stat(*sdp, &mst) == 0) {
1.5       sjg      1459:                                found = 1;
                   1460:                                p = *sdp;
                   1461:                            }
                   1462:                        }
                   1463:                        if (found) {
1.7       sjg      1464: #ifdef DEBUG_META_MODE
                   1465:                            if (DEBUG(META))
                   1466:                                fprintf(debug_file, "%s: %d: found: %s\n", fname, lineno, p);
                   1467: #endif
1.113     rillig   1468:                            if (!S_ISDIR(mst.mst_mode) &&
                   1469:                                mst.mst_mtime > gn->mtime) {
1.5       sjg      1470:                                if (DEBUG(META))
                   1471:                                    fprintf(debug_file, "%s: %d: file '%s' is newer than the target...\n", fname, lineno, p);
                   1472:                                oodate = TRUE;
1.113     rillig   1473:                            } else if (S_ISDIR(mst.mst_mode)) {
1.5       sjg      1474:                                /* Update the latest directory. */
1.59      sjg      1475:                                cached_realpath(p, latestdir);
1.5       sjg      1476:                            }
                   1477:                        } else if (errno == ENOENT && *p == '/' &&
                   1478:                                   strncmp(p, cwd, cwdlen) != 0) {
                   1479:                            /*
                   1480:                             * A referenced file outside of CWD is missing.
                   1481:                             * We cannot catch every eventuality here...
                   1482:                             */
1.109     rillig   1483:                            if (Lst_Find(missingFiles, string_match, p) == NULL)
1.106     rillig   1484:                                Lst_Append(missingFiles, bmake_strdup(p));
1.4       sjg      1485:                        }
1.1       sjg      1486:                    }
1.38      sjg      1487:                    if (buf[0] == 'E') {
                   1488:                        /* previous latestdir is no longer relevant */
                   1489:                        strlcpy(latestdir, lcwd, sizeof(latestdir));
                   1490:                    }
1.1       sjg      1491:                    break;
                   1492:                default:
                   1493:                    break;
                   1494:                }
1.33      sjg      1495:                if (!oodate && buf[0] == 'L' && link_src != NULL)
                   1496:                    goto check_link_src;
1.5       sjg      1497:            } else if (strcmp(buf, "CMD") == 0) {
1.1       sjg      1498:                /*
                   1499:                 * Compare the current command with the one in the
                   1500:                 * meta data file.
                   1501:                 */
1.115   ! rillig   1502:                if (cmdNode == NULL) {
1.1       sjg      1503:                    if (DEBUG(META))
                   1504:                        fprintf(debug_file, "%s: %d: there were more build commands in the meta data file than there are now...\n", fname, lineno);
                   1505:                    oodate = TRUE;
                   1506:                } else {
1.115   ! rillig   1507:                    char *cmd = LstNode_Datum(cmdNode);
1.29      sjg      1508:                    Boolean hasOODATE = FALSE;
1.1       sjg      1509:
1.29      sjg      1510:                    if (strstr(cmd, "$?"))
                   1511:                        hasOODATE = TRUE;
                   1512:                    else if ((cp = strstr(cmd, ".OODATE"))) {
                   1513:                        /* check for $[{(].OODATE[:)}] */
                   1514:                        if (cp > cmd + 2 && cp[-2] == '$')
                   1515:                            hasOODATE = TRUE;
                   1516:                    }
                   1517:                    if (hasOODATE) {
                   1518:                        needOODATE = TRUE;
                   1519:                        if (DEBUG(META))
                   1520:                            fprintf(debug_file, "%s: %d: cannot compare command using .OODATE\n", fname, lineno);
1.1       sjg      1521:                    }
1.89      rillig   1522:                    cmd = Var_Subst(cmd, gn, VARE_WANTRES|VARE_UNDEFERR);
1.1       sjg      1523:
                   1524:                    if ((cp = strchr(cmd, '\n'))) {
                   1525:                        int n;
                   1526:
                   1527:                        /*
                   1528:                         * This command contains newlines, we need to
                   1529:                         * fetch more from the .meta file before we
                   1530:                         * attempt a comparison.
                   1531:                         */
                   1532:                        /* first put the newline back at buf[x - 1] */
                   1533:                        buf[x - 1] = '\n';
                   1534:                        do {
                   1535:                            /* now fetch the next line */
                   1536:                            if ((n = fgetLine(&buf, &bufsz, x, fp)) <= 0)
                   1537:                                break;
                   1538:                            x = n;
                   1539:                            lineno++;
                   1540:                            if (buf[x - 1] != '\n') {
                   1541:                                warnx("%s: %d: line truncated at %u", fname, lineno, x);
                   1542:                                break;
                   1543:                            }
                   1544:                            cp = strchr(++cp, '\n');
                   1545:                        } while (cp);
                   1546:                        if (buf[x - 1] == '\n')
                   1547:                            buf[x - 1] = '\0';
                   1548:                    }
1.81      sjg      1549:                    if (p &&
                   1550:                        !hasOODATE &&
1.1       sjg      1551:                        !(gn->type & OP_NOMETA_CMP) &&
                   1552:                        strcmp(p, cmd) != 0) {
                   1553:                        if (DEBUG(META))
                   1554:                            fprintf(debug_file, "%s: %d: a build command has changed\n%s\nvs\n%s\n", fname, lineno, p, cmd);
                   1555:                        if (!metaIgnoreCMDs)
                   1556:                            oodate = TRUE;
                   1557:                    }
                   1558:                    free(cmd);
1.115   ! rillig   1559:                    cmdNode = LstNode_Next(cmdNode);
1.1       sjg      1560:                }
                   1561:            } else if (strcmp(buf, "CWD") == 0) {
1.14      sjg      1562:                /*
                   1563:                 * Check if there are extra commands now
                   1564:                 * that weren't in the meta data file.
                   1565:                 */
1.115   ! rillig   1566:                if (!oodate && cmdNode != NULL) {
1.14      sjg      1567:                    if (DEBUG(META))
                   1568:                        fprintf(debug_file, "%s: %d: there are extra build commands now that weren't in the meta data file\n", fname, lineno);
                   1569:                    oodate = TRUE;
                   1570:                }
1.80      sjg      1571:                CHECK_VALID_META(p);
1.11      sjg      1572:                if (strcmp(p, cwd) != 0) {
1.1       sjg      1573:                    if (DEBUG(META))
                   1574:                        fprintf(debug_file, "%s: %d: the current working directory has changed from '%s' to '%s'\n", fname, lineno, p, curdir);
                   1575:                    oodate = TRUE;
                   1576:                }
                   1577:            }
                   1578:        }
                   1579:
                   1580:        fclose(fp);
1.106     rillig   1581:        if (!Lst_IsEmpty(missingFiles)) {
1.17      sjg      1582:            if (DEBUG(META))
                   1583:                fprintf(debug_file, "%s: missing files: %s...\n",
1.112     rillig   1584:                        fname, (char *)LstNode_Datum(Lst_First(missingFiles)));
1.17      sjg      1585:            oodate = TRUE;
                   1586:        }
1.60      sjg      1587:        if (!oodate && !have_filemon && filemonMissing) {
1.21      sjg      1588:            if (DEBUG(META))
1.60      sjg      1589:                fprintf(debug_file, "%s: missing filemon data\n", fname);
1.21      sjg      1590:            oodate = TRUE;
                   1591:        }
1.60      sjg      1592:     } else {
1.86      sjg      1593:        if (writeMeta && (metaMissing || (gn->type & OP_META))) {
1.60      sjg      1594:            cp = NULL;
1.50      christos 1595:
1.60      sjg      1596:            /* if target is in .CURDIR we do not need a meta file */
                   1597:            if (gn->path && (cp = strrchr(gn->path, '/')) && cp > gn->path) {
                   1598:                if (strncmp(curdir, gn->path, (cp - gn->path)) != 0) {
                   1599:                    cp = NULL;          /* not in .CURDIR */
                   1600:                }
                   1601:            }
                   1602:            if (!cp) {
                   1603:                if (DEBUG(META))
                   1604:                    fprintf(debug_file, "%s: required but missing\n", fname);
                   1605:                oodate = TRUE;
1.62      sjg      1606:                needOODATE = TRUE;      /* assume the worst */
1.60      sjg      1607:            }
                   1608:        }
1.58      sjg      1609:     }
                   1610:
1.106     rillig   1611:     Lst_Destroy(missingFiles, free);
1.50      christos 1612:
1.26      sjg      1613:     if (oodate && needOODATE) {
1.4       sjg      1614:        /*
1.26      sjg      1615:         * Target uses .OODATE which is empty; or we wouldn't be here.
                   1616:         * We have decided it is oodate, so .OODATE needs to be set.
                   1617:         * All we can sanely do is set it to .ALLSRC.
1.4       sjg      1618:         */
                   1619:        Var_Delete(OODATE, gn);
1.83      rillig   1620:        Var_Set(OODATE, Var_Value(ALLSRC, gn, &cp), gn);
1.91      rillig   1621:        bmake_free(cp);
1.4       sjg      1622:     }
1.58      sjg      1623:
                   1624:  oodate_out:
                   1625:     for (i--; i >= 0; i--) {
1.91      rillig   1626:        bmake_free(pa[i]);
1.58      sjg      1627:     }
1.1       sjg      1628:     return oodate;
                   1629: }
                   1630:
                   1631: /* support for compat mode */
                   1632:
                   1633: static int childPipe[2];
                   1634:
                   1635: void
                   1636: meta_compat_start(void)
                   1637: {
1.73      maxv     1638: #ifdef USE_FILEMON_ONCE
                   1639:     /*
                   1640:      * We need to re-open filemon for each cmd.
                   1641:      */
                   1642:     BuildMon *pbm = &Mybm;
1.85      rillig   1643:
1.73      maxv     1644:     if (pbm->mfp != NULL && useFilemon) {
1.74      riastrad 1645:        meta_open_filemon(pbm);
1.73      maxv     1646:     } else {
1.74      riastrad 1647:        pbm->mon_fd = -1;
                   1648:        pbm->filemon = NULL;
1.73      maxv     1649:     }
                   1650: #endif
1.1       sjg      1651:     if (pipe(childPipe) < 0)
                   1652:        Punt("Cannot create pipe: %s", strerror(errno));
                   1653:     /* Set close-on-exec flag for both */
1.42      christos 1654:     (void)fcntl(childPipe[0], F_SETFD, FD_CLOEXEC);
                   1655:     (void)fcntl(childPipe[1], F_SETFD, FD_CLOEXEC);
1.1       sjg      1656: }
                   1657:
                   1658: void
                   1659: meta_compat_child(void)
                   1660: {
                   1661:     meta_job_child(NULL);
                   1662:     if (dup2(childPipe[1], 1) < 0 ||
                   1663:        dup2(1, 2) < 0) {
                   1664:        execError("dup2", "pipe");
                   1665:        _exit(1);
                   1666:     }
                   1667: }
                   1668:
                   1669: void
1.74      riastrad 1670: meta_compat_parent(pid_t child)
1.1       sjg      1671: {
1.74      riastrad 1672:     int outfd, metafd, maxfd, nfds;
1.78      sjg      1673:     char buf[BUFSIZ+1];
1.74      riastrad 1674:     fd_set readfds;
                   1675:
                   1676:     meta_job_parent(NULL, child);
1.1       sjg      1677:     close(childPipe[1]);                       /* child side */
1.74      riastrad 1678:     outfd = childPipe[0];
1.79      sjg      1679: #ifdef USE_FILEMON
1.78      sjg      1680:     metafd = Mybm.filemon ? filemon_readfd(Mybm.filemon) : -1;
1.79      sjg      1681: #else
                   1682:     metafd = -1;
                   1683: #endif
1.74      riastrad 1684:     maxfd = -1;
                   1685:     if (outfd > maxfd)
                   1686:            maxfd = outfd;
                   1687:     if (metafd > maxfd)
                   1688:            maxfd = metafd;
                   1689:
                   1690:     while (outfd != -1 || metafd != -1) {
                   1691:        FD_ZERO(&readfds);
                   1692:        if (outfd != -1) {
                   1693:            FD_SET(outfd, &readfds);
                   1694:        }
                   1695:        if (metafd != -1) {
                   1696:            FD_SET(metafd, &readfds);
                   1697:        }
                   1698:        nfds = select(maxfd + 1, &readfds, NULL, NULL, NULL);
                   1699:        if (nfds == -1) {
                   1700:            if (errno == EINTR)
                   1701:                continue;
                   1702:            err(1, "select");
                   1703:        }
                   1704:
                   1705:        if (outfd != -1 && FD_ISSET(outfd, &readfds)) do {
                   1706:            /* XXX this is not line-buffered */
1.78      sjg      1707:            ssize_t nread = read(outfd, buf, sizeof(buf) - 1);
1.74      riastrad 1708:            if (nread == -1)
                   1709:                err(1, "read");
                   1710:            if (nread == 0) {
                   1711:                close(outfd);
                   1712:                outfd = -1;
                   1713:                break;
                   1714:            }
                   1715:            fwrite(buf, 1, (size_t)nread, stdout);
                   1716:            fflush(stdout);
1.78      sjg      1717:            buf[nread] = '\0';
                   1718:            meta_job_output(NULL, buf, "");
1.74      riastrad 1719:        } while (0);
                   1720:        if (metafd != -1 && FD_ISSET(metafd, &readfds)) {
                   1721:            if (meta_job_event(NULL) <= 0)
                   1722:                metafd = -1;
                   1723:        }
1.1       sjg      1724:     }
                   1725: }
1.3       sjg      1726:
                   1727: #endif /* USE_META */

CVSweb <webmaster@jp.NetBSD.org>