1*98875883SSimon J. Gerraty /* $NetBSD: meta.c,v 1.206 2023/08/19 00:09:17 sjg Exp $ */ 23955d011SMarcel Moolenaar 33955d011SMarcel Moolenaar /* 43955d011SMarcel Moolenaar * Implement 'meta' mode. 53955d011SMarcel Moolenaar * Adapted from John Birrell's patches to FreeBSD make. 63955d011SMarcel Moolenaar * --sjg 73955d011SMarcel Moolenaar */ 83955d011SMarcel Moolenaar /* 9be19d90bSSimon J. Gerraty * Copyright (c) 2009-2016, Juniper Networks, Inc. 103955d011SMarcel Moolenaar * Portions Copyright (c) 2009, John Birrell. 113955d011SMarcel Moolenaar * 123955d011SMarcel Moolenaar * Redistribution and use in source and binary forms, with or without 133955d011SMarcel Moolenaar * modification, are permitted provided that the following conditions 143955d011SMarcel Moolenaar * are met: 153955d011SMarcel Moolenaar * 1. Redistributions of source code must retain the above copyright 163955d011SMarcel Moolenaar * notice, this list of conditions and the following disclaimer. 173955d011SMarcel Moolenaar * 2. Redistributions in binary form must reproduce the above copyright 183955d011SMarcel Moolenaar * notice, this list of conditions and the following disclaimer in the 193955d011SMarcel Moolenaar * documentation and/or other materials provided with the distribution. 203955d011SMarcel Moolenaar * 213955d011SMarcel Moolenaar * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 223955d011SMarcel Moolenaar * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 233955d011SMarcel Moolenaar * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 243955d011SMarcel Moolenaar * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 253955d011SMarcel Moolenaar * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 263955d011SMarcel Moolenaar * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 273955d011SMarcel Moolenaar * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 283955d011SMarcel Moolenaar * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 293955d011SMarcel Moolenaar * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 303955d011SMarcel Moolenaar * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 313955d011SMarcel Moolenaar * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 323955d011SMarcel Moolenaar */ 333955d011SMarcel Moolenaar #if defined(USE_META) 343955d011SMarcel Moolenaar 353955d011SMarcel Moolenaar #ifdef HAVE_CONFIG_H 363955d011SMarcel Moolenaar # include "config.h" 373955d011SMarcel Moolenaar #endif 383955d011SMarcel Moolenaar #include <sys/stat.h> 39ac3446e9SSimon J. Gerraty #ifdef HAVE_LIBGEN_H 403955d011SMarcel Moolenaar #include <libgen.h> 41ac3446e9SSimon J. Gerraty #elif !defined(HAVE_DIRNAME) 42ac3446e9SSimon J. Gerraty char * dirname(char *); 43ac3446e9SSimon J. Gerraty #endif 443955d011SMarcel Moolenaar #include <errno.h> 453955d011SMarcel Moolenaar #if !defined(HAVE_CONFIG_H) || defined(HAVE_ERR_H) 463955d011SMarcel Moolenaar #include <err.h> 473955d011SMarcel Moolenaar #endif 483955d011SMarcel Moolenaar 493955d011SMarcel Moolenaar #include "make.h" 502c3632d1SSimon J. Gerraty #include "dir.h" 513955d011SMarcel Moolenaar #include "job.h" 523955d011SMarcel Moolenaar 5349caa483SSimon J. Gerraty #ifdef USE_FILEMON 5449caa483SSimon J. Gerraty #include "filemon/filemon.h" 553955d011SMarcel Moolenaar #endif 563955d011SMarcel Moolenaar 573955d011SMarcel Moolenaar static BuildMon Mybm; /* for compat */ 5806b9b3e0SSimon J. Gerraty static StringList metaBailiwick = LST_INIT; /* our scope of control */ 59be19d90bSSimon J. Gerraty static char *metaBailiwickStr; /* string storage for the list */ 6006b9b3e0SSimon J. Gerraty static StringList metaIgnorePaths = LST_INIT; /* paths we deliberately ignore */ 61be19d90bSSimon J. Gerraty static char *metaIgnorePathsStr; /* string storage for the list */ 6251ee2c1cSSimon J. Gerraty 6351ee2c1cSSimon J. Gerraty #ifndef MAKE_META_IGNORE_PATHS 6451ee2c1cSSimon J. Gerraty #define MAKE_META_IGNORE_PATHS ".MAKE.META.IGNORE_PATHS" 6551ee2c1cSSimon J. Gerraty #endif 66e48f47ddSSimon J. Gerraty #ifndef MAKE_META_IGNORE_PATTERNS 67e48f47ddSSimon J. Gerraty #define MAKE_META_IGNORE_PATTERNS ".MAKE.META.IGNORE_PATTERNS" 68e48f47ddSSimon J. Gerraty #endif 6995e3ed2cSSimon J. Gerraty #ifndef MAKE_META_IGNORE_FILTER 7095e3ed2cSSimon J. Gerraty #define MAKE_META_IGNORE_FILTER ".MAKE.META.IGNORE_FILTER" 7195e3ed2cSSimon J. Gerraty #endif 729f45a3c8SSimon J. Gerraty #ifndef MAKE_META_CMP_FILTER 739f45a3c8SSimon J. Gerraty #define MAKE_META_CMP_FILTER ".MAKE.META.CMP_FILTER" 749f45a3c8SSimon J. Gerraty #endif 753955d011SMarcel Moolenaar 76b0c40a00SSimon J. Gerraty bool useMeta = false; 77b0c40a00SSimon J. Gerraty static bool useFilemon = false; 78b0c40a00SSimon J. Gerraty static bool writeMeta = false; 79b0c40a00SSimon J. Gerraty static bool metaMissing = false; /* oodate if missing */ 80b0c40a00SSimon J. Gerraty static bool filemonMissing = false; /* oodate if missing */ 81b0c40a00SSimon J. Gerraty static bool metaEnv = false; /* don't save env unless asked */ 82b0c40a00SSimon J. Gerraty static bool metaVerbose = false; 83b0c40a00SSimon J. Gerraty static bool metaIgnoreCMDs = false; /* ignore CMDs in .meta files */ 84b0c40a00SSimon J. Gerraty static bool metaIgnorePatterns = false; /* do we need to do pattern matches */ 85b0c40a00SSimon J. Gerraty static bool metaIgnoreFilter = false; /* do we have more complex filtering? */ 869f45a3c8SSimon J. Gerraty static bool metaCmpFilter = false; /* do we have CMP_FILTER ? */ 87b0c40a00SSimon J. Gerraty static bool metaCurdirOk = false; /* write .meta in .CURDIR Ok? */ 88b0c40a00SSimon J. Gerraty static bool metaSilent = false; /* if we have a .meta be SILENT */ 893955d011SMarcel Moolenaar 903955d011SMarcel Moolenaar 913955d011SMarcel Moolenaar #define MAKE_META_PREFIX ".MAKE.META.PREFIX" 923955d011SMarcel Moolenaar 933955d011SMarcel Moolenaar #ifndef N2U 943955d011SMarcel Moolenaar # define N2U(n, u) (((n) + ((u) - 1)) / (u)) 953955d011SMarcel Moolenaar #endif 963955d011SMarcel Moolenaar #ifndef ROUNDUP 973955d011SMarcel Moolenaar # define ROUNDUP(n, u) (N2U((n), (u)) * (u)) 983955d011SMarcel Moolenaar #endif 993955d011SMarcel Moolenaar 1003955d011SMarcel Moolenaar #if !defined(HAVE_STRSEP) 101e2eeea75SSimon J. Gerraty # define strsep(s, d) stresep((s), (d), '\0') 1023955d011SMarcel Moolenaar #endif 10312904384SSimon J. Gerraty #if !defined(HAVE_STRESEP) 10412904384SSimon J. Gerraty char * stresep(char **, const char *, int); 10512904384SSimon J. Gerraty #endif 1063955d011SMarcel Moolenaar 1073955d011SMarcel Moolenaar /* 1083955d011SMarcel Moolenaar * Filemon is a kernel module which snoops certain syscalls. 1093955d011SMarcel Moolenaar * 1103955d011SMarcel Moolenaar * C chdir 1113955d011SMarcel Moolenaar * E exec 1123955d011SMarcel Moolenaar * F [v]fork 1133955d011SMarcel Moolenaar * L [sym]link 1143955d011SMarcel Moolenaar * M rename 1153955d011SMarcel Moolenaar * R read 1163955d011SMarcel Moolenaar * W write 1173955d011SMarcel Moolenaar * S stat 1183955d011SMarcel Moolenaar * 1193955d011SMarcel Moolenaar * See meta_oodate below - we mainly care about 'E' and 'R'. 1203955d011SMarcel Moolenaar * 1213955d011SMarcel Moolenaar * We can still use meta mode without filemon, but 1223955d011SMarcel Moolenaar * the benefits are more limited. 1233955d011SMarcel Moolenaar */ 1243955d011SMarcel Moolenaar #ifdef USE_FILEMON 1253955d011SMarcel Moolenaar 1263955d011SMarcel Moolenaar /* 1273955d011SMarcel Moolenaar * Open the filemon device. 1283955d011SMarcel Moolenaar */ 1293955d011SMarcel Moolenaar static void 13049caa483SSimon J. Gerraty meta_open_filemon(BuildMon *pbm) 1313955d011SMarcel Moolenaar { 13249caa483SSimon J. Gerraty int dupfd; 1333955d011SMarcel Moolenaar 13449caa483SSimon J. Gerraty pbm->mon_fd = -1; 13549caa483SSimon J. Gerraty pbm->filemon = NULL; 13606b9b3e0SSimon J. Gerraty if (!useFilemon || pbm->mfp == NULL) 1373955d011SMarcel Moolenaar return; 1383955d011SMarcel Moolenaar 13949caa483SSimon J. Gerraty pbm->filemon = filemon_open(); 14049caa483SSimon J. Gerraty if (pbm->filemon == NULL) { 141b0c40a00SSimon J. Gerraty useFilemon = false; 14249caa483SSimon J. Gerraty warn("Could not open filemon %s", filemon_path()); 1433955d011SMarcel Moolenaar return; 1443955d011SMarcel Moolenaar } 1453955d011SMarcel Moolenaar 1463955d011SMarcel Moolenaar /* 1473955d011SMarcel Moolenaar * We use a file outside of '.' 1483955d011SMarcel Moolenaar * to avoid a FreeBSD kernel bug where unlink invalidates 1493955d011SMarcel Moolenaar * cwd causing getcwd to do a lot more work. 1503955d011SMarcel Moolenaar * We only care about the descriptor. 1513955d011SMarcel Moolenaar */ 152dba7b0efSSimon J. Gerraty if (!opts.compatMake) 153dba7b0efSSimon J. Gerraty pbm->mon_fd = Job_TempFile("filemon.XXXXXX", NULL, 0); 154dba7b0efSSimon J. Gerraty else 155dba7b0efSSimon J. Gerraty pbm->mon_fd = mkTempFile("filemon.XXXXXX", NULL, 0); 15649caa483SSimon J. Gerraty if ((dupfd = dup(pbm->mon_fd)) == -1) { 15712904384SSimon J. Gerraty Punt("Could not dup filemon output: %s", strerror(errno)); 15849caa483SSimon J. Gerraty } 15949caa483SSimon J. Gerraty (void)fcntl(dupfd, F_SETFD, FD_CLOEXEC); 16049caa483SSimon J. Gerraty if (filemon_setfd(pbm->filemon, dupfd) == -1) { 16112904384SSimon J. Gerraty Punt("Could not set filemon file descriptor: %s", strerror(errno)); 1623955d011SMarcel Moolenaar } 1633955d011SMarcel Moolenaar /* we don't need these once we exec */ 164be19d90bSSimon J. Gerraty (void)fcntl(pbm->mon_fd, F_SETFD, FD_CLOEXEC); 1653955d011SMarcel Moolenaar } 1663955d011SMarcel Moolenaar 1673955d011SMarcel Moolenaar /* 1683955d011SMarcel Moolenaar * Read the build monitor output file and write records to the target's 1693955d011SMarcel Moolenaar * metadata file. 1703955d011SMarcel Moolenaar */ 171e48f47ddSSimon J. Gerraty static int 1723955d011SMarcel Moolenaar filemon_read(FILE *mfp, int fd) 1733955d011SMarcel Moolenaar { 1743955d011SMarcel Moolenaar char buf[BUFSIZ]; 175e48f47ddSSimon J. Gerraty int error; 1763955d011SMarcel Moolenaar 1773955d011SMarcel Moolenaar /* Check if we're not writing to a meta data file.*/ 1783955d011SMarcel Moolenaar if (mfp == NULL) { 1793955d011SMarcel Moolenaar if (fd >= 0) 1803955d011SMarcel Moolenaar close(fd); /* not interested */ 181e48f47ddSSimon J. Gerraty return 0; 1823955d011SMarcel Moolenaar } 1833955d011SMarcel Moolenaar /* rewind */ 1843841c287SSimon J. Gerraty if (lseek(fd, (off_t)0, SEEK_SET) < 0) { 1853841c287SSimon J. Gerraty error = errno; 1863841c287SSimon J. Gerraty warn("Could not rewind filemon"); 1873841c287SSimon J. Gerraty fprintf(mfp, "\n"); 1883841c287SSimon J. Gerraty } else { 189956e45f6SSimon J. Gerraty ssize_t n; 190956e45f6SSimon J. Gerraty 191e48f47ddSSimon J. Gerraty error = 0; 192bedf67aeSSimon J. Gerraty fprintf(mfp, "\n-- filemon acquired metadata --\n"); 1933955d011SMarcel Moolenaar 194e2eeea75SSimon J. Gerraty while ((n = read(fd, buf, sizeof buf)) > 0) { 195956e45f6SSimon J. Gerraty if ((ssize_t)fwrite(buf, 1, (size_t)n, mfp) < n) 196e48f47ddSSimon J. Gerraty error = EIO; 1973955d011SMarcel Moolenaar } 1983841c287SSimon J. Gerraty } 19912904384SSimon J. Gerraty if (fflush(mfp) != 0) 20012904384SSimon J. Gerraty Punt("Cannot write filemon data to meta file: %s", 20112904384SSimon J. Gerraty strerror(errno)); 202e48f47ddSSimon J. Gerraty if (close(fd) < 0) 203e48f47ddSSimon J. Gerraty error = errno; 204e48f47ddSSimon J. Gerraty return error; 2053955d011SMarcel Moolenaar } 2063955d011SMarcel Moolenaar #endif 2073955d011SMarcel Moolenaar 2083955d011SMarcel Moolenaar /* 2093955d011SMarcel Moolenaar * when realpath() fails, 2103955d011SMarcel Moolenaar * we use this, to clean up ./ and ../ 2113955d011SMarcel Moolenaar */ 2123955d011SMarcel Moolenaar static void 2139f45a3c8SSimon J. Gerraty eat_dots(char *buf) 2143955d011SMarcel Moolenaar { 2159f45a3c8SSimon J. Gerraty char *p; 2163955d011SMarcel Moolenaar 2179f45a3c8SSimon J. Gerraty while ((p = strstr(buf, "/./")) != NULL) 2189f45a3c8SSimon J. Gerraty memmove(p, p + 2, strlen(p + 2) + 1); 2193955d011SMarcel Moolenaar 2209f45a3c8SSimon J. Gerraty while ((p = strstr(buf, "/../")) != NULL) { 2219f45a3c8SSimon J. Gerraty char *p2 = p + 3; 2229f45a3c8SSimon J. Gerraty if (p > buf) { 2233955d011SMarcel Moolenaar do { 2249f45a3c8SSimon J. Gerraty p--; 2259f45a3c8SSimon J. Gerraty } while (p > buf && *p != '/'); 2263955d011SMarcel Moolenaar } 2279f45a3c8SSimon J. Gerraty if (*p == '/') 2289f45a3c8SSimon J. Gerraty memmove(p, p2, strlen(p2) + 1); 2299f45a3c8SSimon J. Gerraty else 2303955d011SMarcel Moolenaar return; /* can't happen? */ 2313955d011SMarcel Moolenaar } 2323955d011SMarcel Moolenaar } 2333955d011SMarcel Moolenaar 2343955d011SMarcel Moolenaar static char * 2351ce939a7SSimon J. Gerraty meta_name(char *mname, size_t mnamelen, 2363955d011SMarcel Moolenaar const char *dname, 237b778b302SSimon J. Gerraty const char *tname, 238b778b302SSimon J. Gerraty const char *cwd) 2393955d011SMarcel Moolenaar { 2403955d011SMarcel Moolenaar char buf[MAXPATHLEN]; 24112904384SSimon J. Gerraty char *rp, *cp; 24212904384SSimon J. Gerraty const char *tname_base; 2433955d011SMarcel Moolenaar char *tp; 244e22fef7dSSimon J. Gerraty char *dtp; 245e22fef7dSSimon J. Gerraty size_t ldname; 2463955d011SMarcel Moolenaar 2473955d011SMarcel Moolenaar /* 2483955d011SMarcel Moolenaar * Weed out relative paths from the target file name. 2493955d011SMarcel Moolenaar * We have to be careful though since if target is a 2503955d011SMarcel Moolenaar * symlink, the result will be unstable. 2513955d011SMarcel Moolenaar * So we use realpath() just to get the dirname, and leave the 2523955d011SMarcel Moolenaar * basename as given to us. 2533955d011SMarcel Moolenaar */ 25412904384SSimon J. Gerraty if ((tname_base = strrchr(tname, '/')) != NULL) { 25506b9b3e0SSimon J. Gerraty if (cached_realpath(tname, buf) != NULL) { 25606b9b3e0SSimon J. Gerraty if ((rp = strrchr(buf, '/')) != NULL) { 2573955d011SMarcel Moolenaar rp++; 25812904384SSimon J. Gerraty tname_base++; 25912904384SSimon J. Gerraty if (strcmp(tname_base, rp) != 0) 26012904384SSimon J. Gerraty strlcpy(rp, tname_base, sizeof buf - (size_t)(rp - buf)); 2613955d011SMarcel Moolenaar } 2623955d011SMarcel Moolenaar tname = buf; 2633955d011SMarcel Moolenaar } else { 2643955d011SMarcel Moolenaar /* 2653955d011SMarcel Moolenaar * We likely have a directory which is about to be made. 2663955d011SMarcel Moolenaar * We pretend realpath() succeeded, to have a chance 2673955d011SMarcel Moolenaar * of generating the same meta file name that we will 2683955d011SMarcel Moolenaar * next time through. 2693955d011SMarcel Moolenaar */ 2703955d011SMarcel Moolenaar if (tname[0] == '/') { 271e2eeea75SSimon J. Gerraty strlcpy(buf, tname, sizeof buf); 2723955d011SMarcel Moolenaar } else { 273e2eeea75SSimon J. Gerraty snprintf(buf, sizeof buf, "%s/%s", cwd, tname); 2743955d011SMarcel Moolenaar } 2759f45a3c8SSimon J. Gerraty eat_dots(buf); 2763955d011SMarcel Moolenaar tname = buf; 2773955d011SMarcel Moolenaar } 2783955d011SMarcel Moolenaar } 2793955d011SMarcel Moolenaar /* on some systems dirname may modify its arg */ 2803955d011SMarcel Moolenaar tp = bmake_strdup(tname); 281e22fef7dSSimon J. Gerraty dtp = dirname(tp); 2824fde40d9SSimon J. Gerraty if (strcmp(dname, dtp) == 0) { 2834fde40d9SSimon J. Gerraty if (snprintf(mname, mnamelen, "%s.meta", tname) >= (int)mnamelen) 2844fde40d9SSimon J. Gerraty mname[mnamelen - 1] = '\0'; 2854fde40d9SSimon J. Gerraty } else { 2864fde40d9SSimon J. Gerraty int x; 2874fde40d9SSimon J. Gerraty 288e22fef7dSSimon J. Gerraty ldname = strlen(dname); 289e22fef7dSSimon J. Gerraty if (strncmp(dname, dtp, ldname) == 0 && dtp[ldname] == '/') 2904fde40d9SSimon J. Gerraty x = snprintf(mname, mnamelen, "%s/%s.meta", dname, &tname[ldname+1]); 291e22fef7dSSimon J. Gerraty else 2924fde40d9SSimon J. Gerraty x = snprintf(mname, mnamelen, "%s/%s.meta", dname, tname); 2934fde40d9SSimon J. Gerraty if (x >= (int)mnamelen) 2944fde40d9SSimon J. Gerraty mname[mnamelen - 1] = '\0'; 2953955d011SMarcel Moolenaar /* 2963955d011SMarcel Moolenaar * Replace path separators in the file name after the 2973955d011SMarcel Moolenaar * current object directory path. 2983955d011SMarcel Moolenaar */ 2993955d011SMarcel Moolenaar cp = mname + strlen(dname) + 1; 3003955d011SMarcel Moolenaar 3013955d011SMarcel Moolenaar while (*cp != '\0') { 3023955d011SMarcel Moolenaar if (*cp == '/') 3033955d011SMarcel Moolenaar *cp = '_'; 3043955d011SMarcel Moolenaar cp++; 3053955d011SMarcel Moolenaar } 3063955d011SMarcel Moolenaar } 3073955d011SMarcel Moolenaar free(tp); 3083841c287SSimon J. Gerraty return mname; 3093955d011SMarcel Moolenaar } 3103955d011SMarcel Moolenaar 3113955d011SMarcel Moolenaar /* 3123955d011SMarcel Moolenaar * Return true if running ${.MAKE} 3133955d011SMarcel Moolenaar * Bypassed if target is flagged .MAKE 3143955d011SMarcel Moolenaar */ 315b0c40a00SSimon J. Gerraty static bool 31606b9b3e0SSimon J. Gerraty is_submake(const char *cmd, GNode *gn) 3173955d011SMarcel Moolenaar { 3182c3632d1SSimon J. Gerraty static const char *p_make = NULL; 319956e45f6SSimon J. Gerraty static size_t p_len; 3203955d011SMarcel Moolenaar char *mp = NULL; 3219f45a3c8SSimon J. Gerraty const char *cp2; 322b0c40a00SSimon J. Gerraty bool rc = false; 3233955d011SMarcel Moolenaar 324e2eeea75SSimon J. Gerraty if (p_make == NULL) { 325dba7b0efSSimon J. Gerraty p_make = Var_Value(gn, ".MAKE").str; 3263955d011SMarcel Moolenaar p_len = strlen(p_make); 3273955d011SMarcel Moolenaar } 3289f45a3c8SSimon J. Gerraty if (strchr(cmd, '$') != NULL) { 3298c973ee2SSimon J. Gerraty mp = Var_Subst(cmd, gn, VARE_WANTRES); 330956e45f6SSimon J. Gerraty /* TODO: handle errors */ 3313955d011SMarcel Moolenaar cmd = mp; 3323955d011SMarcel Moolenaar } 3333955d011SMarcel Moolenaar cp2 = strstr(cmd, p_make); 334e2eeea75SSimon J. Gerraty if (cp2 != NULL) { 3353955d011SMarcel Moolenaar switch (cp2[p_len]) { 3363955d011SMarcel Moolenaar case '\0': 3373955d011SMarcel Moolenaar case ' ': 3383955d011SMarcel Moolenaar case '\t': 3393955d011SMarcel Moolenaar case '\n': 340b0c40a00SSimon J. Gerraty rc = true; 3413955d011SMarcel Moolenaar break; 3423955d011SMarcel Moolenaar } 34306b9b3e0SSimon J. Gerraty if (cp2 > cmd && rc) { 3443955d011SMarcel Moolenaar switch (cp2[-1]) { 3453955d011SMarcel Moolenaar case ' ': 3463955d011SMarcel Moolenaar case '\t': 3473955d011SMarcel Moolenaar case '\n': 3483955d011SMarcel Moolenaar break; 3493955d011SMarcel Moolenaar default: 350b0c40a00SSimon J. Gerraty rc = false; /* no match */ 3513955d011SMarcel Moolenaar break; 3523955d011SMarcel Moolenaar } 3533955d011SMarcel Moolenaar } 3543955d011SMarcel Moolenaar } 3553955d011SMarcel Moolenaar free(mp); 3563841c287SSimon J. Gerraty return rc; 3573955d011SMarcel Moolenaar } 3583955d011SMarcel Moolenaar 359b0c40a00SSimon J. Gerraty static bool 36006b9b3e0SSimon J. Gerraty any_is_submake(GNode *gn) 36106b9b3e0SSimon J. Gerraty { 36206b9b3e0SSimon J. Gerraty StringListNode *ln; 36306b9b3e0SSimon J. Gerraty 36406b9b3e0SSimon J. Gerraty for (ln = gn->commands.first; ln != NULL; ln = ln->next) 36506b9b3e0SSimon J. Gerraty if (is_submake(ln->datum, gn)) 366b0c40a00SSimon J. Gerraty return true; 367b0c40a00SSimon J. Gerraty return false; 36806b9b3e0SSimon J. Gerraty } 3693955d011SMarcel Moolenaar 370956e45f6SSimon J. Gerraty static void 371b0c40a00SSimon J. Gerraty printCMD(const char *ucmd, FILE *fp, GNode *gn) 3723955d011SMarcel Moolenaar { 373b0c40a00SSimon J. Gerraty FStr xcmd = FStr_InitRefer(ucmd); 3743955d011SMarcel Moolenaar 3759f45a3c8SSimon J. Gerraty Var_Expand(&xcmd, gn, VARE_WANTRES); 376b0c40a00SSimon J. Gerraty fprintf(fp, "CMD %s\n", xcmd.str); 377b0c40a00SSimon J. Gerraty FStr_Done(&xcmd); 378956e45f6SSimon J. Gerraty } 379956e45f6SSimon J. Gerraty 380956e45f6SSimon J. Gerraty static void 38106b9b3e0SSimon J. Gerraty printCMDs(GNode *gn, FILE *fp) 382956e45f6SSimon J. Gerraty { 38306b9b3e0SSimon J. Gerraty StringListNode *ln; 384956e45f6SSimon J. Gerraty 38506b9b3e0SSimon J. Gerraty for (ln = gn->commands.first; ln != NULL; ln = ln->next) 38606b9b3e0SSimon J. Gerraty printCMD(ln->datum, fp, gn); 3873955d011SMarcel Moolenaar } 3883955d011SMarcel Moolenaar 3893955d011SMarcel Moolenaar /* 3903955d011SMarcel Moolenaar * Certain node types never get a .meta file 3913955d011SMarcel Moolenaar */ 3922f2a5ecdSSimon J. Gerraty #define SKIP_META_TYPE(flag, str) do { \ 3932f2a5ecdSSimon J. Gerraty if ((gn->type & (flag))) { \ 3942f2a5ecdSSimon J. Gerraty if (verbose) \ 3952f2a5ecdSSimon J. Gerraty debug_printf("Skipping meta for %s: .%s\n", gn->name, str); \ 396b0c40a00SSimon J. Gerraty return false; \ 3973955d011SMarcel Moolenaar } \ 39812904384SSimon J. Gerraty } while (false) 3993955d011SMarcel Moolenaar 400b778b302SSimon J. Gerraty 401b778b302SSimon J. Gerraty /* 402b778b302SSimon J. Gerraty * Do we need/want a .meta file ? 403b778b302SSimon J. Gerraty */ 404b0c40a00SSimon J. Gerraty static bool 4051ce939a7SSimon J. Gerraty meta_needed(GNode *gn, const char *dname, 406b0c40a00SSimon J. Gerraty char *objdir_realpath, bool verbose) 407b778b302SSimon J. Gerraty { 408e2eeea75SSimon J. Gerraty struct cached_stat cst; 409b778b302SSimon J. Gerraty 410b778b302SSimon J. Gerraty if (verbose) 411b778b302SSimon J. Gerraty verbose = DEBUG(META); 412b778b302SSimon J. Gerraty 413b778b302SSimon J. Gerraty /* This may be a phony node which we don't want meta data for... */ 414b778b302SSimon J. Gerraty /* Skip .meta for .BEGIN, .END, .ERROR etc as well. */ 415b778b302SSimon J. Gerraty /* Or it may be explicitly flagged as .NOMETA */ 4162f2a5ecdSSimon J. Gerraty SKIP_META_TYPE(OP_NOMETA, "NOMETA"); 417b778b302SSimon J. Gerraty /* Unless it is explicitly flagged as .META */ 418b778b302SSimon J. Gerraty if (!(gn->type & OP_META)) { 4192f2a5ecdSSimon J. Gerraty SKIP_META_TYPE(OP_PHONY, "PHONY"); 4202f2a5ecdSSimon J. Gerraty SKIP_META_TYPE(OP_SPECIAL, "SPECIAL"); 4212f2a5ecdSSimon J. Gerraty SKIP_META_TYPE(OP_MAKE, "MAKE"); 422b778b302SSimon J. Gerraty } 423b778b302SSimon J. Gerraty 424b778b302SSimon J. Gerraty /* Check if there are no commands to execute. */ 42506b9b3e0SSimon J. Gerraty if (Lst_IsEmpty(&gn->commands)) { 426b778b302SSimon J. Gerraty if (verbose) 427956e45f6SSimon J. Gerraty debug_printf("Skipping meta for %s: no commands\n", gn->name); 428b0c40a00SSimon J. Gerraty return false; 429b778b302SSimon J. Gerraty } 430b778b302SSimon J. Gerraty if ((gn->type & (OP_META|OP_SUBMAKE)) == OP_SUBMAKE) { 431b778b302SSimon J. Gerraty /* OP_SUBMAKE is a bit too aggressive */ 43206b9b3e0SSimon J. Gerraty if (any_is_submake(gn)) { 433956e45f6SSimon J. Gerraty DEBUG1(META, "Skipping meta for %s: .SUBMAKE\n", gn->name); 434b0c40a00SSimon J. Gerraty return false; 435b778b302SSimon J. Gerraty } 436b778b302SSimon J. Gerraty } 437b778b302SSimon J. Gerraty 438b778b302SSimon J. Gerraty /* The object directory may not exist. Check it.. */ 439e2eeea75SSimon J. Gerraty if (cached_stat(dname, &cst) != 0) { 440b778b302SSimon J. Gerraty if (verbose) 441956e45f6SSimon J. Gerraty debug_printf("Skipping meta for %s: no .OBJDIR\n", gn->name); 442b0c40a00SSimon J. Gerraty return false; 443b778b302SSimon J. Gerraty } 444b778b302SSimon J. Gerraty 445b778b302SSimon J. Gerraty /* make sure these are canonical */ 44606b9b3e0SSimon J. Gerraty if (cached_realpath(dname, objdir_realpath) != NULL) 44706b9b3e0SSimon J. Gerraty dname = objdir_realpath; 448b778b302SSimon J. Gerraty 449b778b302SSimon J. Gerraty /* If we aren't in the object directory, don't create a meta file. */ 450b778b302SSimon J. Gerraty if (!metaCurdirOk && strcmp(curdir, dname) == 0) { 451b778b302SSimon J. Gerraty if (verbose) 452956e45f6SSimon J. Gerraty debug_printf("Skipping meta for %s: .OBJDIR == .CURDIR\n", 453b778b302SSimon J. Gerraty gn->name); 454b0c40a00SSimon J. Gerraty return false; 455b778b302SSimon J. Gerraty } 456b0c40a00SSimon J. Gerraty return true; 457b778b302SSimon J. Gerraty } 458b778b302SSimon J. Gerraty 459b778b302SSimon J. Gerraty 4603955d011SMarcel Moolenaar static FILE * 4613955d011SMarcel Moolenaar meta_create(BuildMon *pbm, GNode *gn) 4623955d011SMarcel Moolenaar { 46306b9b3e0SSimon J. Gerraty FILE *fp; 4643955d011SMarcel Moolenaar char buf[MAXPATHLEN]; 46506b9b3e0SSimon J. Gerraty char objdir_realpath[MAXPATHLEN]; 4663955d011SMarcel Moolenaar char **ptr; 46706b9b3e0SSimon J. Gerraty FStr dname; 4683955d011SMarcel Moolenaar const char *tname; 4693955d011SMarcel Moolenaar char *fname; 4703955d011SMarcel Moolenaar const char *cp; 4713955d011SMarcel Moolenaar 47206b9b3e0SSimon J. Gerraty fp = NULL; 4733955d011SMarcel Moolenaar 474dba7b0efSSimon J. Gerraty dname = Var_Value(gn, ".OBJDIR"); 475956e45f6SSimon J. Gerraty tname = GNode_VarTarget(gn); 4763955d011SMarcel Moolenaar 47706b9b3e0SSimon J. Gerraty /* if this succeeds objdir_realpath is realpath of dname */ 478b0c40a00SSimon J. Gerraty if (!meta_needed(gn, dname.str, objdir_realpath, true)) 4793955d011SMarcel Moolenaar goto out; 48006b9b3e0SSimon J. Gerraty dname.str = objdir_realpath; 4813955d011SMarcel Moolenaar 4823955d011SMarcel Moolenaar if (metaVerbose) { 4833955d011SMarcel Moolenaar /* Describe the target we are building */ 4848c973ee2SSimon J. Gerraty char *mp = Var_Subst("${" MAKE_META_PREFIX "}", gn, VARE_WANTRES); 485956e45f6SSimon J. Gerraty /* TODO: handle errors */ 48606b9b3e0SSimon J. Gerraty if (mp[0] != '\0') 4873955d011SMarcel Moolenaar fprintf(stdout, "%s\n", mp); 4883955d011SMarcel Moolenaar free(mp); 4893955d011SMarcel Moolenaar } 4903955d011SMarcel Moolenaar /* Get the basename of the target */ 49106b9b3e0SSimon J. Gerraty cp = str_basename(tname); 4923955d011SMarcel Moolenaar 4933955d011SMarcel Moolenaar fflush(stdout); 4943955d011SMarcel Moolenaar 4953955d011SMarcel Moolenaar if (!writeMeta) 4963955d011SMarcel Moolenaar /* Don't create meta data. */ 4973955d011SMarcel Moolenaar goto out; 4983955d011SMarcel Moolenaar 499e2eeea75SSimon J. Gerraty fname = meta_name(pbm->meta_fname, sizeof pbm->meta_fname, 50006b9b3e0SSimon J. Gerraty dname.str, tname, objdir_realpath); 5013955d011SMarcel Moolenaar 5023955d011SMarcel Moolenaar #ifdef DEBUG_META_MODE 503956e45f6SSimon J. Gerraty DEBUG1(META, "meta_create: %s\n", fname); 5043955d011SMarcel Moolenaar #endif 5053955d011SMarcel Moolenaar 50606b9b3e0SSimon J. Gerraty if ((fp = fopen(fname, "w")) == NULL) 50712904384SSimon J. Gerraty Punt("Could not open meta file '%s': %s", fname, strerror(errno)); 5083955d011SMarcel Moolenaar 50906b9b3e0SSimon J. Gerraty fprintf(fp, "# Meta data file %s\n", fname); 5103955d011SMarcel Moolenaar 51106b9b3e0SSimon J. Gerraty printCMDs(gn, fp); 5123955d011SMarcel Moolenaar 51306b9b3e0SSimon J. Gerraty fprintf(fp, "CWD %s\n", getcwd(buf, sizeof buf)); 51406b9b3e0SSimon J. Gerraty fprintf(fp, "TARGET %s\n", tname); 515956e45f6SSimon J. Gerraty cp = GNode_VarOodate(gn); 51606b9b3e0SSimon J. Gerraty if (cp != NULL && *cp != '\0') { 51706b9b3e0SSimon J. Gerraty fprintf(fp, "OODATE %s\n", cp); 51849caa483SSimon J. Gerraty } 5193955d011SMarcel Moolenaar if (metaEnv) { 5203955d011SMarcel Moolenaar for (ptr = environ; *ptr != NULL; ptr++) 52106b9b3e0SSimon J. Gerraty fprintf(fp, "ENV %s\n", *ptr); 5223955d011SMarcel Moolenaar } 5233955d011SMarcel Moolenaar 52406b9b3e0SSimon J. Gerraty fprintf(fp, "-- command output --\n"); 52512904384SSimon J. Gerraty if (fflush(fp) != 0) 52612904384SSimon J. Gerraty Punt("Cannot write expanded command to meta file: %s", 52712904384SSimon J. Gerraty strerror(errno)); 5283955d011SMarcel Moolenaar 529dba7b0efSSimon J. Gerraty Global_Append(".MAKE.META.FILES", fname); 530dba7b0efSSimon J. Gerraty Global_Append(".MAKE.META.CREATED", fname); 5313955d011SMarcel Moolenaar 5323955d011SMarcel Moolenaar gn->type |= OP_META; /* in case anyone wants to know */ 5333955d011SMarcel Moolenaar if (metaSilent) { 5343955d011SMarcel Moolenaar gn->type |= OP_SILENT; 5353955d011SMarcel Moolenaar } 5363955d011SMarcel Moolenaar out: 53706b9b3e0SSimon J. Gerraty FStr_Done(&dname); 5383955d011SMarcel Moolenaar 53906b9b3e0SSimon J. Gerraty return fp; 5403955d011SMarcel Moolenaar } 5413955d011SMarcel Moolenaar 542b0c40a00SSimon J. Gerraty static bool 54312904384SSimon J. Gerraty boolValue(const char *s) 5443955d011SMarcel Moolenaar { 5453955d011SMarcel Moolenaar switch (*s) { 5463955d011SMarcel Moolenaar case '0': 5473955d011SMarcel Moolenaar case 'N': 5483955d011SMarcel Moolenaar case 'n': 5493955d011SMarcel Moolenaar case 'F': 5503955d011SMarcel Moolenaar case 'f': 551b0c40a00SSimon J. Gerraty return false; 5523955d011SMarcel Moolenaar } 553b0c40a00SSimon J. Gerraty return true; 5543955d011SMarcel Moolenaar } 5553955d011SMarcel Moolenaar 5561748de26SSimon J. Gerraty /* 5571748de26SSimon J. Gerraty * Initialization we need before reading makefiles. 5581748de26SSimon J. Gerraty */ 5593955d011SMarcel Moolenaar void 56052d86256SSimon J. Gerraty meta_init(void) 5611748de26SSimon J. Gerraty { 5621748de26SSimon J. Gerraty #ifdef USE_FILEMON 5631748de26SSimon J. Gerraty /* this allows makefiles to test if we have filemon support */ 564dba7b0efSSimon J. Gerraty Global_Set(".MAKE.PATH_FILEMON", filemon_path()); 5651748de26SSimon J. Gerraty #endif 5661748de26SSimon J. Gerraty } 5671748de26SSimon J. Gerraty 5681748de26SSimon J. Gerraty 569b778b302SSimon J. Gerraty #define get_mode_bf(bf, token) \ 57006b9b3e0SSimon J. Gerraty if ((cp = strstr(make_mode, token)) != NULL) \ 571e2eeea75SSimon J. Gerraty bf = boolValue(cp + sizeof (token) - 1) 572b778b302SSimon J. Gerraty 5731748de26SSimon J. Gerraty /* 5741748de26SSimon J. Gerraty * Initialization we need after reading makefiles. 5751748de26SSimon J. Gerraty */ 5761748de26SSimon J. Gerraty void 5771748de26SSimon J. Gerraty meta_mode_init(const char *make_mode) 5783955d011SMarcel Moolenaar { 579b0c40a00SSimon J. Gerraty static bool once = false; 58012904384SSimon J. Gerraty const char *cp; 5813955d011SMarcel Moolenaar 582b0c40a00SSimon J. Gerraty useMeta = true; 583b0c40a00SSimon J. Gerraty useFilemon = true; 584b0c40a00SSimon J. Gerraty writeMeta = true; 5853955d011SMarcel Moolenaar 58606b9b3e0SSimon J. Gerraty if (make_mode != NULL) { 58706b9b3e0SSimon J. Gerraty if (strstr(make_mode, "env") != NULL) 588b0c40a00SSimon J. Gerraty metaEnv = true; 58906b9b3e0SSimon J. Gerraty if (strstr(make_mode, "verb") != NULL) 590b0c40a00SSimon J. Gerraty metaVerbose = true; 59106b9b3e0SSimon J. Gerraty if (strstr(make_mode, "read") != NULL) 592b0c40a00SSimon J. Gerraty writeMeta = false; 59306b9b3e0SSimon J. Gerraty if (strstr(make_mode, "nofilemon") != NULL) 594b0c40a00SSimon J. Gerraty useFilemon = false; 59506b9b3e0SSimon J. Gerraty if (strstr(make_mode, "ignore-cmd") != NULL) 596b0c40a00SSimon J. Gerraty metaIgnoreCMDs = true; 597b778b302SSimon J. Gerraty if (useFilemon) 598b778b302SSimon J. Gerraty get_mode_bf(filemonMissing, "missing-filemon="); 599b778b302SSimon J. Gerraty get_mode_bf(metaCurdirOk, "curdirok="); 600b778b302SSimon J. Gerraty get_mode_bf(metaMissing, "missing-meta="); 601b778b302SSimon J. Gerraty get_mode_bf(metaSilent, "silent="); 6023955d011SMarcel Moolenaar } 603dba7b0efSSimon J. Gerraty if (metaVerbose && !Var_Exists(SCOPE_GLOBAL, MAKE_META_PREFIX)) { 6043955d011SMarcel Moolenaar /* 6053955d011SMarcel Moolenaar * The default value for MAKE_META_PREFIX 6063955d011SMarcel Moolenaar * prints the absolute path of the target. 6073955d011SMarcel Moolenaar * This works be cause :H will generate '.' if there is no / 6083955d011SMarcel Moolenaar * and :tA will resolve that to cwd. 6093955d011SMarcel Moolenaar */ 610dba7b0efSSimon J. Gerraty Global_Set(MAKE_META_PREFIX, 611dba7b0efSSimon J. Gerraty "Building ${.TARGET:H:tA}/${.TARGET:T}"); 6123955d011SMarcel Moolenaar } 6133955d011SMarcel Moolenaar if (once) 6143955d011SMarcel Moolenaar return; 615b0c40a00SSimon J. Gerraty once = true; 616e2eeea75SSimon J. Gerraty memset(&Mybm, 0, sizeof Mybm); 6173955d011SMarcel Moolenaar /* 6183955d011SMarcel Moolenaar * We consider ourselves master of all within ${.MAKE.META.BAILIWICK} 6193955d011SMarcel Moolenaar */ 6208c973ee2SSimon J. Gerraty metaBailiwickStr = Var_Subst("${.MAKE.META.BAILIWICK:O:u:tA}", 6218c973ee2SSimon J. Gerraty SCOPE_GLOBAL, VARE_WANTRES); 622956e45f6SSimon J. Gerraty /* TODO: handle errors */ 62306b9b3e0SSimon J. Gerraty str2Lst_Append(&metaBailiwick, metaBailiwickStr); 62451ee2c1cSSimon J. Gerraty /* 62551ee2c1cSSimon J. Gerraty * We ignore any paths that start with ${.MAKE.META.IGNORE_PATHS} 62651ee2c1cSSimon J. Gerraty */ 627dba7b0efSSimon J. Gerraty Global_Append(MAKE_META_IGNORE_PATHS, 628dba7b0efSSimon J. Gerraty "/dev /etc /proc /tmp /var/run /var/tmp ${TMPDIR}"); 6298c973ee2SSimon J. Gerraty metaIgnorePathsStr = Var_Subst("${" MAKE_META_IGNORE_PATHS ":O:u:tA}", 6308c973ee2SSimon J. Gerraty SCOPE_GLOBAL, VARE_WANTRES); 631956e45f6SSimon J. Gerraty /* TODO: handle errors */ 63206b9b3e0SSimon J. Gerraty str2Lst_Append(&metaIgnorePaths, metaIgnorePathsStr); 633e48f47ddSSimon J. Gerraty 634e48f47ddSSimon J. Gerraty /* 635e48f47ddSSimon J. Gerraty * We ignore any paths that match ${.MAKE.META.IGNORE_PATTERNS} 636e48f47ddSSimon J. Gerraty */ 6379f45a3c8SSimon J. Gerraty metaIgnorePatterns = Var_Exists(SCOPE_GLOBAL, MAKE_META_IGNORE_PATTERNS); 6389f45a3c8SSimon J. Gerraty metaIgnoreFilter = Var_Exists(SCOPE_GLOBAL, MAKE_META_IGNORE_FILTER); 6399f45a3c8SSimon J. Gerraty metaCmpFilter = Var_Exists(SCOPE_GLOBAL, MAKE_META_CMP_FILTER); 6403955d011SMarcel Moolenaar } 6413955d011SMarcel Moolenaar 6428c973ee2SSimon J. Gerraty MAKE_INLINE BuildMon * 6438c973ee2SSimon J. Gerraty BM(Job *job) 6448c973ee2SSimon J. Gerraty { 6458c973ee2SSimon J. Gerraty 6468c973ee2SSimon J. Gerraty return ((job != NULL) ? &job->bm : &Mybm); 6478c973ee2SSimon J. Gerraty } 6488c973ee2SSimon J. Gerraty 6493955d011SMarcel Moolenaar /* 6503955d011SMarcel Moolenaar * In each case below we allow for job==NULL 6513955d011SMarcel Moolenaar */ 6523955d011SMarcel Moolenaar void 6533955d011SMarcel Moolenaar meta_job_start(Job *job, GNode *gn) 6543955d011SMarcel Moolenaar { 6553955d011SMarcel Moolenaar BuildMon *pbm; 6563955d011SMarcel Moolenaar 6578c973ee2SSimon J. Gerraty pbm = BM(job); 6583955d011SMarcel Moolenaar pbm->mfp = meta_create(pbm, gn); 6593955d011SMarcel Moolenaar #ifdef USE_FILEMON_ONCE 6603955d011SMarcel Moolenaar /* compat mode we open the filemon dev once per command */ 6613955d011SMarcel Moolenaar if (job == NULL) 6623955d011SMarcel Moolenaar return; 6633955d011SMarcel Moolenaar #endif 6643955d011SMarcel Moolenaar #ifdef USE_FILEMON 6653955d011SMarcel Moolenaar if (pbm->mfp != NULL && useFilemon) { 66649caa483SSimon J. Gerraty meta_open_filemon(pbm); 6673955d011SMarcel Moolenaar } else { 66849caa483SSimon J. Gerraty pbm->mon_fd = -1; 66949caa483SSimon J. Gerraty pbm->filemon = NULL; 6703955d011SMarcel Moolenaar } 6713955d011SMarcel Moolenaar #endif 6723955d011SMarcel Moolenaar } 6733955d011SMarcel Moolenaar 6743955d011SMarcel Moolenaar /* 6753955d011SMarcel Moolenaar * The child calls this before doing anything. 6763955d011SMarcel Moolenaar * It does not disturb our state. 6773955d011SMarcel Moolenaar */ 6783955d011SMarcel Moolenaar void 6791d3f2ddcSSimon J. Gerraty meta_job_child(Job *job MAKE_ATTR_UNUSED) 6803955d011SMarcel Moolenaar { 6813955d011SMarcel Moolenaar #ifdef USE_FILEMON 6823955d011SMarcel Moolenaar BuildMon *pbm; 6833955d011SMarcel Moolenaar 6848c973ee2SSimon J. Gerraty pbm = BM(job); 685db29cad8SSimon J. Gerraty if (pbm->mfp != NULL) { 686db29cad8SSimon J. Gerraty close(fileno(pbm->mfp)); 68706b9b3e0SSimon J. Gerraty if (useFilemon && pbm->filemon != NULL) { 688db29cad8SSimon J. Gerraty pid_t pid; 689db29cad8SSimon J. Gerraty 6903955d011SMarcel Moolenaar pid = getpid(); 69149caa483SSimon J. Gerraty if (filemon_setpid_child(pbm->filemon, pid) == -1) { 69212904384SSimon J. Gerraty Punt("Could not set filemon pid: %s", strerror(errno)); 6933955d011SMarcel Moolenaar } 6943955d011SMarcel Moolenaar } 695db29cad8SSimon J. Gerraty } 6963955d011SMarcel Moolenaar #endif 6973955d011SMarcel Moolenaar } 6983955d011SMarcel Moolenaar 6993955d011SMarcel Moolenaar void 7001d3f2ddcSSimon J. Gerraty meta_job_parent(Job *job MAKE_ATTR_UNUSED, pid_t pid MAKE_ATTR_UNUSED) 70149caa483SSimon J. Gerraty { 70249caa483SSimon J. Gerraty #if defined(USE_FILEMON) && !defined(USE_FILEMON_DEV) 70349caa483SSimon J. Gerraty BuildMon *pbm; 70449caa483SSimon J. Gerraty 7058c973ee2SSimon J. Gerraty pbm = BM(job); 70606b9b3e0SSimon J. Gerraty if (useFilemon && pbm->filemon != NULL) { 70749caa483SSimon J. Gerraty filemon_setpid_parent(pbm->filemon, pid); 70849caa483SSimon J. Gerraty } 70949caa483SSimon J. Gerraty #endif 71049caa483SSimon J. Gerraty } 71149caa483SSimon J. Gerraty 71249caa483SSimon J. Gerraty int 7131d3f2ddcSSimon J. Gerraty meta_job_fd(Job *job MAKE_ATTR_UNUSED) 71449caa483SSimon J. Gerraty { 71549caa483SSimon J. Gerraty #if defined(USE_FILEMON) && !defined(USE_FILEMON_DEV) 71649caa483SSimon J. Gerraty BuildMon *pbm; 71749caa483SSimon J. Gerraty 7188c973ee2SSimon J. Gerraty pbm = BM(job); 71906b9b3e0SSimon J. Gerraty if (useFilemon && pbm->filemon != NULL) { 72049caa483SSimon J. Gerraty return filemon_readfd(pbm->filemon); 72149caa483SSimon J. Gerraty } 72249caa483SSimon J. Gerraty #endif 72349caa483SSimon J. Gerraty return -1; 72449caa483SSimon J. Gerraty } 72549caa483SSimon J. Gerraty 72649caa483SSimon J. Gerraty int 7271d3f2ddcSSimon J. Gerraty meta_job_event(Job *job MAKE_ATTR_UNUSED) 72849caa483SSimon J. Gerraty { 72949caa483SSimon J. Gerraty #if defined(USE_FILEMON) && !defined(USE_FILEMON_DEV) 73049caa483SSimon J. Gerraty BuildMon *pbm; 73149caa483SSimon J. Gerraty 7328c973ee2SSimon J. Gerraty pbm = BM(job); 73306b9b3e0SSimon J. Gerraty if (useFilemon && pbm->filemon != NULL) { 73449caa483SSimon J. Gerraty return filemon_process(pbm->filemon); 73549caa483SSimon J. Gerraty } 73649caa483SSimon J. Gerraty #endif 73749caa483SSimon J. Gerraty return 0; 73849caa483SSimon J. Gerraty } 73949caa483SSimon J. Gerraty 74049caa483SSimon J. Gerraty void 741b0c40a00SSimon J. Gerraty meta_job_error(Job *job, GNode *gn, bool ignerr, int status) 7423955d011SMarcel Moolenaar { 7433955d011SMarcel Moolenaar char cwd[MAXPATHLEN]; 7443955d011SMarcel Moolenaar BuildMon *pbm; 7453955d011SMarcel Moolenaar 7468c973ee2SSimon J. Gerraty pbm = BM(job); 7478c973ee2SSimon J. Gerraty if (job != NULL && gn == NULL) 7483955d011SMarcel Moolenaar gn = job->node; 7493955d011SMarcel Moolenaar if (pbm->mfp != NULL) { 7508695518cSSimon J. Gerraty fprintf(pbm->mfp, "\n*** Error code %d%s\n", 75106b9b3e0SSimon J. Gerraty status, ignerr ? "(ignored)" : ""); 7523955d011SMarcel Moolenaar } 753dba7b0efSSimon J. Gerraty if (gn != NULL) 754dba7b0efSSimon J. Gerraty Global_Set(".ERROR_TARGET", GNode_Path(gn)); 7554fde40d9SSimon J. Gerraty if (getcwd(cwd, sizeof cwd) == NULL) 7564fde40d9SSimon J. Gerraty Punt("Cannot get cwd: %s", strerror(errno)); 7574fde40d9SSimon J. Gerraty 758dba7b0efSSimon J. Gerraty Global_Set(".ERROR_CWD", cwd); 759e2eeea75SSimon J. Gerraty if (pbm->meta_fname[0] != '\0') { 760dba7b0efSSimon J. Gerraty Global_Set(".ERROR_META_FILE", pbm->meta_fname); 7613955d011SMarcel Moolenaar } 7623955d011SMarcel Moolenaar meta_job_finish(job); 7633955d011SMarcel Moolenaar } 7643955d011SMarcel Moolenaar 7653955d011SMarcel Moolenaar void 7663955d011SMarcel Moolenaar meta_job_output(Job *job, char *cp, const char *nl) 7673955d011SMarcel Moolenaar { 7683955d011SMarcel Moolenaar BuildMon *pbm; 7693955d011SMarcel Moolenaar 7708c973ee2SSimon J. Gerraty pbm = BM(job); 7713955d011SMarcel Moolenaar if (pbm->mfp != NULL) { 7723955d011SMarcel Moolenaar if (metaVerbose) { 7733955d011SMarcel Moolenaar static char *meta_prefix = NULL; 774956e45f6SSimon J. Gerraty static size_t meta_prefix_len; 7753955d011SMarcel Moolenaar 776e2eeea75SSimon J. Gerraty if (meta_prefix == NULL) { 7773955d011SMarcel Moolenaar char *cp2; 7783955d011SMarcel Moolenaar 7798c973ee2SSimon J. Gerraty meta_prefix = Var_Subst("${" MAKE_META_PREFIX "}", 7808c973ee2SSimon J. Gerraty SCOPE_GLOBAL, VARE_WANTRES); 781956e45f6SSimon J. Gerraty /* TODO: handle errors */ 78206b9b3e0SSimon J. Gerraty if ((cp2 = strchr(meta_prefix, '$')) != NULL) 783956e45f6SSimon J. Gerraty meta_prefix_len = (size_t)(cp2 - meta_prefix); 7843955d011SMarcel Moolenaar else 7853955d011SMarcel Moolenaar meta_prefix_len = strlen(meta_prefix); 7863955d011SMarcel Moolenaar } 7873955d011SMarcel Moolenaar if (strncmp(cp, meta_prefix, meta_prefix_len) == 0) { 7883955d011SMarcel Moolenaar cp = strchr(cp + 1, '\n'); 78906b9b3e0SSimon J. Gerraty if (cp == NULL) 7903955d011SMarcel Moolenaar return; 79106b9b3e0SSimon J. Gerraty cp++; 7923955d011SMarcel Moolenaar } 7933955d011SMarcel Moolenaar } 7943955d011SMarcel Moolenaar fprintf(pbm->mfp, "%s%s", cp, nl); 7953955d011SMarcel Moolenaar } 7963955d011SMarcel Moolenaar } 7973955d011SMarcel Moolenaar 798e48f47ddSSimon J. Gerraty int 7993955d011SMarcel Moolenaar meta_cmd_finish(void *pbmp) 8003955d011SMarcel Moolenaar { 801e48f47ddSSimon J. Gerraty int error = 0; 8023955d011SMarcel Moolenaar BuildMon *pbm = pbmp; 80350d2e745SSimon J. Gerraty #ifdef USE_FILEMON 804e48f47ddSSimon J. Gerraty int x; 80550d2e745SSimon J. Gerraty #endif 8063955d011SMarcel Moolenaar 807e2eeea75SSimon J. Gerraty if (pbm == NULL) 8083955d011SMarcel Moolenaar pbm = &Mybm; 8093955d011SMarcel Moolenaar 8108695518cSSimon J. Gerraty #ifdef USE_FILEMON 81106b9b3e0SSimon J. Gerraty if (pbm->filemon != NULL) { 81249caa483SSimon J. Gerraty while (filemon_process(pbm->filemon) > 0) 81349caa483SSimon J. Gerraty continue; 81412904384SSimon J. Gerraty if (filemon_close(pbm->filemon) == -1) { 815e48f47ddSSimon J. Gerraty error = errno; 81612904384SSimon J. Gerraty Punt("filemon failed: %s", strerror(errno)); 81712904384SSimon J. Gerraty } 818e48f47ddSSimon J. Gerraty x = filemon_read(pbm->mfp, pbm->mon_fd); 819e48f47ddSSimon J. Gerraty if (error == 0 && x != 0) 820e48f47ddSSimon J. Gerraty error = x; 82149caa483SSimon J. Gerraty pbm->mon_fd = -1; 82249caa483SSimon J. Gerraty pbm->filemon = NULL; 823e2eeea75SSimon J. Gerraty return error; 824e2eeea75SSimon J. Gerraty } 8253955d011SMarcel Moolenaar #endif 826e2eeea75SSimon J. Gerraty 8278695518cSSimon J. Gerraty fprintf(pbm->mfp, "\n"); /* ensure end with newline */ 828e48f47ddSSimon J. Gerraty return error; 8293955d011SMarcel Moolenaar } 8303955d011SMarcel Moolenaar 831e48f47ddSSimon J. Gerraty int 8323955d011SMarcel Moolenaar meta_job_finish(Job *job) 8333955d011SMarcel Moolenaar { 8343955d011SMarcel Moolenaar BuildMon *pbm; 835e48f47ddSSimon J. Gerraty int error = 0; 836e48f47ddSSimon J. Gerraty int x; 8373955d011SMarcel Moolenaar 8388c973ee2SSimon J. Gerraty pbm = BM(job); 8393955d011SMarcel Moolenaar if (pbm->mfp != NULL) { 840e48f47ddSSimon J. Gerraty error = meta_cmd_finish(pbm); 841e48f47ddSSimon J. Gerraty x = fclose(pbm->mfp); 842e48f47ddSSimon J. Gerraty if (error == 0 && x != 0) 843e48f47ddSSimon J. Gerraty error = errno; 8443955d011SMarcel Moolenaar pbm->mfp = NULL; 8453955d011SMarcel Moolenaar pbm->meta_fname[0] = '\0'; 8463955d011SMarcel Moolenaar } 847e48f47ddSSimon J. Gerraty return error; 8483955d011SMarcel Moolenaar } 8493955d011SMarcel Moolenaar 850be19d90bSSimon J. Gerraty void 851be19d90bSSimon J. Gerraty meta_finish(void) 852be19d90bSSimon J. Gerraty { 85306b9b3e0SSimon J. Gerraty Lst_Done(&metaBailiwick); 854be19d90bSSimon J. Gerraty free(metaBailiwickStr); 85506b9b3e0SSimon J. Gerraty Lst_Done(&metaIgnorePaths); 856be19d90bSSimon J. Gerraty free(metaIgnorePathsStr); 857be19d90bSSimon J. Gerraty } 858be19d90bSSimon J. Gerraty 8593955d011SMarcel Moolenaar /* 8603955d011SMarcel Moolenaar * Fetch a full line from fp - growing bufp if needed 8613955d011SMarcel Moolenaar * Return length in bufp. 8623955d011SMarcel Moolenaar */ 8633955d011SMarcel Moolenaar static int 8643955d011SMarcel Moolenaar fgetLine(char **bufp, size_t *szp, int o, FILE *fp) 8653955d011SMarcel Moolenaar { 8663955d011SMarcel Moolenaar char *buf = *bufp; 8673955d011SMarcel Moolenaar size_t bufsz = *szp; 8683955d011SMarcel Moolenaar struct stat fs; 8693955d011SMarcel Moolenaar int x; 8703955d011SMarcel Moolenaar 871956e45f6SSimon J. Gerraty if (fgets(&buf[o], (int)bufsz - o, fp) != NULL) { 8723955d011SMarcel Moolenaar check_newline: 873956e45f6SSimon J. Gerraty x = o + (int)strlen(&buf[o]); 8743955d011SMarcel Moolenaar if (buf[x - 1] == '\n') 8753955d011SMarcel Moolenaar return x; 8763955d011SMarcel Moolenaar /* 8773955d011SMarcel Moolenaar * We need to grow the buffer. 8783955d011SMarcel Moolenaar * The meta file can give us a clue. 8793955d011SMarcel Moolenaar */ 8803955d011SMarcel Moolenaar if (fstat(fileno(fp), &fs) == 0) { 8813955d011SMarcel Moolenaar size_t newsz; 8823955d011SMarcel Moolenaar char *p; 8833955d011SMarcel Moolenaar 884956e45f6SSimon J. Gerraty newsz = ROUNDUP(((size_t)fs.st_size / 2), BUFSIZ); 8853955d011SMarcel Moolenaar if (newsz <= bufsz) 886956e45f6SSimon J. Gerraty newsz = ROUNDUP((size_t)fs.st_size, BUFSIZ); 8878695518cSSimon J. Gerraty if (newsz <= bufsz) 8888695518cSSimon J. Gerraty return x; /* truncated */ 88906b9b3e0SSimon J. Gerraty DEBUG2(META, "growing buffer %u -> %u\n", 89006b9b3e0SSimon J. Gerraty (unsigned)bufsz, (unsigned)newsz); 8913955d011SMarcel Moolenaar p = bmake_realloc(buf, newsz); 8923955d011SMarcel Moolenaar *bufp = buf = p; 8933955d011SMarcel Moolenaar *szp = bufsz = newsz; 8943955d011SMarcel Moolenaar /* fetch the rest */ 895e2eeea75SSimon J. Gerraty if (fgets(&buf[x], (int)bufsz - x, fp) == NULL) 8963955d011SMarcel Moolenaar return x; /* truncated! */ 8973955d011SMarcel Moolenaar goto check_newline; 8983955d011SMarcel Moolenaar } 8993955d011SMarcel Moolenaar } 9003955d011SMarcel Moolenaar return 0; 9013955d011SMarcel Moolenaar } 9023955d011SMarcel Moolenaar 903b0c40a00SSimon J. Gerraty static bool 90406b9b3e0SSimon J. Gerraty prefix_match(const char *prefix, const char *path) 9053955d011SMarcel Moolenaar { 9063955d011SMarcel Moolenaar size_t n = strlen(prefix); 9073955d011SMarcel Moolenaar 9083841c287SSimon J. Gerraty return strncmp(path, prefix, n) == 0; 9093955d011SMarcel Moolenaar } 9103955d011SMarcel Moolenaar 911b0c40a00SSimon J. Gerraty static bool 91206b9b3e0SSimon J. Gerraty has_any_prefix(const char *path, StringList *prefixes) 91306b9b3e0SSimon J. Gerraty { 91406b9b3e0SSimon J. Gerraty StringListNode *ln; 91506b9b3e0SSimon J. Gerraty 91606b9b3e0SSimon J. Gerraty for (ln = prefixes->first; ln != NULL; ln = ln->next) 91706b9b3e0SSimon J. Gerraty if (prefix_match(ln->datum, path)) 918b0c40a00SSimon J. Gerraty return true; 919b0c40a00SSimon J. Gerraty return false; 92006b9b3e0SSimon J. Gerraty } 92106b9b3e0SSimon J. Gerraty 9222c3632d1SSimon J. Gerraty /* See if the path equals prefix or starts with "prefix/". */ 923b0c40a00SSimon J. Gerraty static bool 924956e45f6SSimon J. Gerraty path_starts_with(const char *path, const char *prefix) 92595e3ed2cSSimon J. Gerraty { 92695e3ed2cSSimon J. Gerraty size_t n = strlen(prefix); 92795e3ed2cSSimon J. Gerraty 9282c3632d1SSimon J. Gerraty if (strncmp(path, prefix, n) != 0) 929b0c40a00SSimon J. Gerraty return false; 9302c3632d1SSimon J. Gerraty return path[n] == '\0' || path[n] == '/'; 93195e3ed2cSSimon J. Gerraty } 93295e3ed2cSSimon J. Gerraty 933b0c40a00SSimon J. Gerraty static bool 93495e3ed2cSSimon J. Gerraty meta_ignore(GNode *gn, const char *p) 93595e3ed2cSSimon J. Gerraty { 93695e3ed2cSSimon J. Gerraty char fname[MAXPATHLEN]; 93795e3ed2cSSimon J. Gerraty 93895e3ed2cSSimon J. Gerraty if (p == NULL) 939b0c40a00SSimon J. Gerraty return true; 94095e3ed2cSSimon J. Gerraty 94195e3ed2cSSimon J. Gerraty if (*p == '/') { 942*98875883SSimon J. Gerraty /* first try the raw path "as is" */ 943*98875883SSimon J. Gerraty if (has_any_prefix(p, &metaIgnorePaths)) { 944*98875883SSimon J. Gerraty #ifdef DEBUG_META_MODE 945*98875883SSimon J. Gerraty DEBUG1(META, "meta_oodate: ignoring path: %s\n", p); 946*98875883SSimon J. Gerraty #endif 947*98875883SSimon J. Gerraty return true; 948*98875883SSimon J. Gerraty } 94995e3ed2cSSimon J. Gerraty cached_realpath(p, fname); /* clean it up */ 95006b9b3e0SSimon J. Gerraty if (has_any_prefix(fname, &metaIgnorePaths)) { 95195e3ed2cSSimon J. Gerraty #ifdef DEBUG_META_MODE 952956e45f6SSimon J. Gerraty DEBUG1(META, "meta_oodate: ignoring path: %s\n", p); 95395e3ed2cSSimon J. Gerraty #endif 954b0c40a00SSimon J. Gerraty return true; 95595e3ed2cSSimon J. Gerraty } 95695e3ed2cSSimon J. Gerraty } 95795e3ed2cSSimon J. Gerraty 95895e3ed2cSSimon J. Gerraty if (metaIgnorePatterns) { 9592c3632d1SSimon J. Gerraty const char *expr; 96095e3ed2cSSimon J. Gerraty char *pm; 96195e3ed2cSSimon J. Gerraty 962dba7b0efSSimon J. Gerraty /* 963dba7b0efSSimon J. Gerraty * XXX: This variable is set on a target GNode but is not one of 964dba7b0efSSimon J. Gerraty * the usual local variables. It should be deleted afterwards. 965dba7b0efSSimon J. Gerraty * Ideally it would not be created in the first place, just like 966dba7b0efSSimon J. Gerraty * in a .for loop. 967dba7b0efSSimon J. Gerraty */ 968dba7b0efSSimon J. Gerraty Var_Set(gn, ".p.", p); 9692c3632d1SSimon J. Gerraty expr = "${" MAKE_META_IGNORE_PATTERNS ":@m@${.p.:M$m}@}"; 9708c973ee2SSimon J. Gerraty pm = Var_Subst(expr, gn, VARE_WANTRES); 971956e45f6SSimon J. Gerraty /* TODO: handle errors */ 97206b9b3e0SSimon J. Gerraty if (pm[0] != '\0') { 97395e3ed2cSSimon J. Gerraty #ifdef DEBUG_META_MODE 974956e45f6SSimon J. Gerraty DEBUG1(META, "meta_oodate: ignoring pattern: %s\n", p); 97595e3ed2cSSimon J. Gerraty #endif 97695e3ed2cSSimon J. Gerraty free(pm); 977b0c40a00SSimon J. Gerraty return true; 97895e3ed2cSSimon J. Gerraty } 97995e3ed2cSSimon J. Gerraty free(pm); 98095e3ed2cSSimon J. Gerraty } 98195e3ed2cSSimon J. Gerraty 98295e3ed2cSSimon J. Gerraty if (metaIgnoreFilter) { 98395e3ed2cSSimon J. Gerraty char *fm; 98495e3ed2cSSimon J. Gerraty 98595e3ed2cSSimon J. Gerraty /* skip if filter result is empty */ 986e2eeea75SSimon J. Gerraty snprintf(fname, sizeof fname, 98795e3ed2cSSimon J. Gerraty "${%s:L:${%s:ts:}}", 98895e3ed2cSSimon J. Gerraty p, MAKE_META_IGNORE_FILTER); 9898c973ee2SSimon J. Gerraty fm = Var_Subst(fname, gn, VARE_WANTRES); 990956e45f6SSimon J. Gerraty /* TODO: handle errors */ 99195e3ed2cSSimon J. Gerraty if (*fm == '\0') { 99295e3ed2cSSimon J. Gerraty #ifdef DEBUG_META_MODE 993956e45f6SSimon J. Gerraty DEBUG1(META, "meta_oodate: ignoring filtered: %s\n", p); 99495e3ed2cSSimon J. Gerraty #endif 99595e3ed2cSSimon J. Gerraty free(fm); 996b0c40a00SSimon J. Gerraty return true; 99795e3ed2cSSimon J. Gerraty } 99895e3ed2cSSimon J. Gerraty free(fm); 99995e3ed2cSSimon J. Gerraty } 1000b0c40a00SSimon J. Gerraty return false; 100195e3ed2cSSimon J. Gerraty } 100295e3ed2cSSimon J. Gerraty 10033955d011SMarcel Moolenaar /* 10043955d011SMarcel Moolenaar * When running with 'meta' functionality, a target can be out-of-date 1005db29cad8SSimon J. Gerraty * if any of the references in its meta data file is more recent. 10063955d011SMarcel Moolenaar * We have to track the latestdir on a per-process basis. 10073955d011SMarcel Moolenaar */ 1008db29cad8SSimon J. Gerraty #define LCWD_VNAME_FMT ".meta.%d.lcwd" 10093955d011SMarcel Moolenaar #define LDIR_VNAME_FMT ".meta.%d.ldir" 10103955d011SMarcel Moolenaar 10113955d011SMarcel Moolenaar /* 10123955d011SMarcel Moolenaar * It is possible that a .meta file is corrupted, 10133955d011SMarcel Moolenaar * if we detect this we want to reproduce it. 1014b0c40a00SSimon J. Gerraty * Setting oodate true will have that effect. 10153955d011SMarcel Moolenaar */ 101606b9b3e0SSimon J. Gerraty #define CHECK_VALID_META(p) if (!(p != NULL && *p != '\0')) { \ 10179f45a3c8SSimon J. Gerraty warnx("%s: %u: malformed", fname, lineno); \ 1018b0c40a00SSimon J. Gerraty oodate = true; \ 10193955d011SMarcel Moolenaar continue; \ 10203955d011SMarcel Moolenaar } 10213955d011SMarcel Moolenaar 10220dede8b0SSimon J. Gerraty #define DEQUOTE(p) if (*p == '\'') { \ 10230dede8b0SSimon J. Gerraty char *ep; \ 10240dede8b0SSimon J. Gerraty p++; \ 102506b9b3e0SSimon J. Gerraty if ((ep = strchr(p, '\'')) != NULL) \ 10260dede8b0SSimon J. Gerraty *ep = '\0'; \ 10270dede8b0SSimon J. Gerraty } 10280dede8b0SSimon J. Gerraty 1029956e45f6SSimon J. Gerraty static void 1030956e45f6SSimon J. Gerraty append_if_new(StringList *list, const char *str) 1031956e45f6SSimon J. Gerraty { 1032956e45f6SSimon J. Gerraty StringListNode *ln; 1033956e45f6SSimon J. Gerraty 1034956e45f6SSimon J. Gerraty for (ln = list->first; ln != NULL; ln = ln->next) 1035956e45f6SSimon J. Gerraty if (strcmp(ln->datum, str) == 0) 1036956e45f6SSimon J. Gerraty return; 1037956e45f6SSimon J. Gerraty Lst_Append(list, bmake_strdup(str)); 1038956e45f6SSimon J. Gerraty } 1039956e45f6SSimon J. Gerraty 1040a6f0e10bSSimon J. Gerraty /* A "reserved" variable to store the command to be filtered */ 1041a6f0e10bSSimon J. Gerraty #define META_CMD_FILTER_VAR ".MAKE.cmd_filtered" 1042a6f0e10bSSimon J. Gerraty 10439f45a3c8SSimon J. Gerraty static char * 1044a6f0e10bSSimon J. Gerraty meta_filter_cmd(GNode *gn, char *s) 10459f45a3c8SSimon J. Gerraty { 1046a6f0e10bSSimon J. Gerraty Var_Set(gn, META_CMD_FILTER_VAR, s); 10478c973ee2SSimon J. Gerraty s = Var_Subst( 10488c973ee2SSimon J. Gerraty "${" META_CMD_FILTER_VAR ":${" MAKE_META_CMP_FILTER ":ts:}}", 10498c973ee2SSimon J. Gerraty gn, VARE_WANTRES); 10509f45a3c8SSimon J. Gerraty return s; 10519f45a3c8SSimon J. Gerraty } 10529f45a3c8SSimon J. Gerraty 10539f45a3c8SSimon J. Gerraty static int 10549f45a3c8SSimon J. Gerraty meta_cmd_cmp(GNode *gn, char *a, char *b, bool filter) 10559f45a3c8SSimon J. Gerraty { 10569f45a3c8SSimon J. Gerraty int rc; 10579f45a3c8SSimon J. Gerraty 10589f45a3c8SSimon J. Gerraty rc = strcmp(a, b); 10599f45a3c8SSimon J. Gerraty if (rc == 0 || !filter) 10609f45a3c8SSimon J. Gerraty return rc; 1061a6f0e10bSSimon J. Gerraty a = meta_filter_cmd(gn, a); 1062a6f0e10bSSimon J. Gerraty b = meta_filter_cmd(gn, b); 10639f45a3c8SSimon J. Gerraty rc = strcmp(a, b); 10649f45a3c8SSimon J. Gerraty free(a); 10659f45a3c8SSimon J. Gerraty free(b); 1066a6f0e10bSSimon J. Gerraty Var_Delete(gn, META_CMD_FILTER_VAR); 10679f45a3c8SSimon J. Gerraty return rc; 10689f45a3c8SSimon J. Gerraty } 10699f45a3c8SSimon J. Gerraty 1070b0c40a00SSimon J. Gerraty bool 1071b0c40a00SSimon J. Gerraty meta_oodate(GNode *gn, bool oodate) 10723955d011SMarcel Moolenaar { 10733955d011SMarcel Moolenaar static char *tmpdir = NULL; 10743955d011SMarcel Moolenaar static char cwd[MAXPATHLEN]; 1075db29cad8SSimon J. Gerraty char lcwd_vname[64]; 10763955d011SMarcel Moolenaar char ldir_vname[64]; 1077db29cad8SSimon J. Gerraty char lcwd[MAXPATHLEN]; 10783955d011SMarcel Moolenaar char latestdir[MAXPATHLEN]; 10793955d011SMarcel Moolenaar char fname[MAXPATHLEN]; 10803955d011SMarcel Moolenaar char fname1[MAXPATHLEN]; 10813955d011SMarcel Moolenaar char fname2[MAXPATHLEN]; 1082db29cad8SSimon J. Gerraty char fname3[MAXPATHLEN]; 108306b9b3e0SSimon J. Gerraty FStr dname; 1084b778b302SSimon J. Gerraty const char *tname; 10853955d011SMarcel Moolenaar char *p; 10860dede8b0SSimon J. Gerraty char *link_src; 10870dede8b0SSimon J. Gerraty char *move_target; 10883955d011SMarcel Moolenaar static size_t cwdlen = 0; 10893955d011SMarcel Moolenaar static size_t tmplen = 0; 10903955d011SMarcel Moolenaar FILE *fp; 1091b0c40a00SSimon J. Gerraty bool needOODATE = false; 109206b9b3e0SSimon J. Gerraty StringList missingFiles; 1093b0c40a00SSimon J. Gerraty bool have_filemon = false; 10949f45a3c8SSimon J. Gerraty bool cmp_filter; 10953955d011SMarcel Moolenaar 10963955d011SMarcel Moolenaar if (oodate) 10973955d011SMarcel Moolenaar return oodate; /* we're done */ 10983955d011SMarcel Moolenaar 1099dba7b0efSSimon J. Gerraty dname = Var_Value(gn, ".OBJDIR"); 1100956e45f6SSimon J. Gerraty tname = GNode_VarTarget(gn); 1101b778b302SSimon J. Gerraty 1102b778b302SSimon J. Gerraty /* if this succeeds fname3 is realpath of dname */ 1103b0c40a00SSimon J. Gerraty if (!meta_needed(gn, dname.str, fname3, false)) 1104b778b302SSimon J. Gerraty goto oodate_out; 110506b9b3e0SSimon J. Gerraty dname.str = fname3; 1106b778b302SSimon J. Gerraty 110706b9b3e0SSimon J. Gerraty Lst_Init(&missingFiles); 11083955d011SMarcel Moolenaar 11093955d011SMarcel Moolenaar /* 11103955d011SMarcel Moolenaar * We need to check if the target is out-of-date. This includes 11113955d011SMarcel Moolenaar * checking if the expanded command has changed. This in turn 11123955d011SMarcel Moolenaar * requires that all variables are set in the same way that they 11133955d011SMarcel Moolenaar * would be if the target needs to be re-built. 11143955d011SMarcel Moolenaar */ 1115b0c40a00SSimon J. Gerraty GNode_SetLocalVars(gn); 11163955d011SMarcel Moolenaar 111706b9b3e0SSimon J. Gerraty meta_name(fname, sizeof fname, dname.str, tname, dname.str); 11183955d011SMarcel Moolenaar 11193955d011SMarcel Moolenaar #ifdef DEBUG_META_MODE 1120956e45f6SSimon J. Gerraty DEBUG1(META, "meta_oodate: %s\n", fname); 11213955d011SMarcel Moolenaar #endif 11223955d011SMarcel Moolenaar 11233955d011SMarcel Moolenaar if ((fp = fopen(fname, "r")) != NULL) { 11243955d011SMarcel Moolenaar static char *buf = NULL; 11253955d011SMarcel Moolenaar static size_t bufsz; 11269f45a3c8SSimon J. Gerraty unsigned lineno = 0; 11273955d011SMarcel Moolenaar int lastpid = 0; 11283955d011SMarcel Moolenaar int pid; 11293955d011SMarcel Moolenaar int x; 1130956e45f6SSimon J. Gerraty StringListNode *cmdNode; 1131e2eeea75SSimon J. Gerraty struct cached_stat cst; 11323955d011SMarcel Moolenaar 1133e2eeea75SSimon J. Gerraty if (buf == NULL) { 11343955d011SMarcel Moolenaar bufsz = 8 * BUFSIZ; 11353955d011SMarcel Moolenaar buf = bmake_malloc(bufsz); 11363955d011SMarcel Moolenaar } 11373955d011SMarcel Moolenaar 1138e2eeea75SSimon J. Gerraty if (cwdlen == 0) { 1139e2eeea75SSimon J. Gerraty if (getcwd(cwd, sizeof cwd) == NULL) 11403955d011SMarcel Moolenaar err(1, "Could not get current working directory"); 11413955d011SMarcel Moolenaar cwdlen = strlen(cwd); 11423955d011SMarcel Moolenaar } 1143e2eeea75SSimon J. Gerraty strlcpy(lcwd, cwd, sizeof lcwd); 1144e2eeea75SSimon J. Gerraty strlcpy(latestdir, cwd, sizeof latestdir); 11453955d011SMarcel Moolenaar 1146e2eeea75SSimon J. Gerraty if (tmpdir == NULL) { 11473955d011SMarcel Moolenaar tmpdir = getTmpdir(); 11483955d011SMarcel Moolenaar tmplen = strlen(tmpdir); 11493955d011SMarcel Moolenaar } 11503955d011SMarcel Moolenaar 11513955d011SMarcel Moolenaar /* we want to track all the .meta we read */ 1152dba7b0efSSimon J. Gerraty Global_Append(".MAKE.META.FILES", fname); 11533955d011SMarcel Moolenaar 11541d3f2ddcSSimon J. Gerraty cmp_filter = metaCmpFilter || Var_Exists(gn, MAKE_META_CMP_FILTER); 11559f45a3c8SSimon J. Gerraty 115606b9b3e0SSimon J. Gerraty cmdNode = gn->commands.first; 11573955d011SMarcel Moolenaar while (!oodate && (x = fgetLine(&buf, &bufsz, 0, fp)) > 0) { 11583955d011SMarcel Moolenaar lineno++; 11593955d011SMarcel Moolenaar if (buf[x - 1] == '\n') 11603955d011SMarcel Moolenaar buf[x - 1] = '\0'; 11613955d011SMarcel Moolenaar else { 11629f45a3c8SSimon J. Gerraty warnx("%s: %u: line truncated at %u", fname, lineno, x); 1163b0c40a00SSimon J. Gerraty oodate = true; 11643955d011SMarcel Moolenaar break; 11653955d011SMarcel Moolenaar } 11660dede8b0SSimon J. Gerraty link_src = NULL; 11670dede8b0SSimon J. Gerraty move_target = NULL; 11683955d011SMarcel Moolenaar /* Find the start of the build monitor section. */ 1169b778b302SSimon J. Gerraty if (!have_filemon) { 11703955d011SMarcel Moolenaar if (strncmp(buf, "-- filemon", 10) == 0) { 1171b0c40a00SSimon J. Gerraty have_filemon = true; 11723955d011SMarcel Moolenaar continue; 11733955d011SMarcel Moolenaar } 11743955d011SMarcel Moolenaar if (strncmp(buf, "# buildmon", 10) == 0) { 1175b0c40a00SSimon J. Gerraty have_filemon = true; 11763955d011SMarcel Moolenaar continue; 11773955d011SMarcel Moolenaar } 11783955d011SMarcel Moolenaar } 11793955d011SMarcel Moolenaar 11803955d011SMarcel Moolenaar /* Delimit the record type. */ 11813955d011SMarcel Moolenaar p = buf; 11823955d011SMarcel Moolenaar #ifdef DEBUG_META_MODE 11839f45a3c8SSimon J. Gerraty DEBUG3(META, "%s: %u: %s\n", fname, lineno, buf); 11843955d011SMarcel Moolenaar #endif 11853955d011SMarcel Moolenaar strsep(&p, " "); 1186b778b302SSimon J. Gerraty if (have_filemon) { 11873955d011SMarcel Moolenaar /* 11883955d011SMarcel Moolenaar * We are in the 'filemon' output section. 11893955d011SMarcel Moolenaar * Each record from filemon follows the general form: 11903955d011SMarcel Moolenaar * 11913955d011SMarcel Moolenaar * <key> <pid> <data> 11923955d011SMarcel Moolenaar * 11933955d011SMarcel Moolenaar * Where: 11943955d011SMarcel Moolenaar * <key> is a single letter, denoting the syscall. 11953955d011SMarcel Moolenaar * <pid> is the process that made the syscall. 11963955d011SMarcel Moolenaar * <data> is the arguments (of interest). 11973955d011SMarcel Moolenaar */ 11983955d011SMarcel Moolenaar switch(buf[0]) { 11993955d011SMarcel Moolenaar case '#': /* comment */ 12003955d011SMarcel Moolenaar case 'V': /* version */ 12013955d011SMarcel Moolenaar break; 12023955d011SMarcel Moolenaar default: 12033955d011SMarcel Moolenaar /* 12043955d011SMarcel Moolenaar * We need to track pathnames per-process. 12053955d011SMarcel Moolenaar * 1206dba7b0efSSimon J. Gerraty * Each process run by make starts off in the 'CWD' 12073955d011SMarcel Moolenaar * recorded in the .meta file, if it chdirs ('C') 12083955d011SMarcel Moolenaar * elsewhere we need to track that - but only for 12093955d011SMarcel Moolenaar * that process. If it forks ('F'), we initialize 12103955d011SMarcel Moolenaar * the child to have the same cwd as its parent. 12113955d011SMarcel Moolenaar * 12123955d011SMarcel Moolenaar * We also need to track the 'latestdir' of 12133955d011SMarcel Moolenaar * interest. This is usually the same as cwd, but 12143955d011SMarcel Moolenaar * not if a process is reading directories. 12153955d011SMarcel Moolenaar * 12163955d011SMarcel Moolenaar * Each time we spot a different process ('pid') 12173955d011SMarcel Moolenaar * we save the current value of 'latestdir' in a 12183955d011SMarcel Moolenaar * variable qualified by 'lastpid', and 12193955d011SMarcel Moolenaar * re-initialize 'latestdir' to any pre-saved 12203955d011SMarcel Moolenaar * value for the current 'pid' and 'CWD' if none. 12213955d011SMarcel Moolenaar */ 12223955d011SMarcel Moolenaar CHECK_VALID_META(p); 12233955d011SMarcel Moolenaar pid = atoi(p); 12243955d011SMarcel Moolenaar if (pid > 0 && pid != lastpid) { 122506b9b3e0SSimon J. Gerraty FStr ldir; 12263955d011SMarcel Moolenaar 12273955d011SMarcel Moolenaar if (lastpid > 0) { 1228db29cad8SSimon J. Gerraty /* We need to remember these. */ 12299f45a3c8SSimon J. Gerraty Global_Set(lcwd_vname, lcwd); 12309f45a3c8SSimon J. Gerraty Global_Set(ldir_vname, latestdir); 12313955d011SMarcel Moolenaar } 1232e2eeea75SSimon J. Gerraty snprintf(lcwd_vname, sizeof lcwd_vname, LCWD_VNAME_FMT, pid); 1233e2eeea75SSimon J. Gerraty snprintf(ldir_vname, sizeof ldir_vname, LDIR_VNAME_FMT, pid); 12343955d011SMarcel Moolenaar lastpid = pid; 1235dba7b0efSSimon J. Gerraty ldir = Var_Value(SCOPE_GLOBAL, ldir_vname); 123606b9b3e0SSimon J. Gerraty if (ldir.str != NULL) { 123706b9b3e0SSimon J. Gerraty strlcpy(latestdir, ldir.str, sizeof latestdir); 123806b9b3e0SSimon J. Gerraty FStr_Done(&ldir); 1239db29cad8SSimon J. Gerraty } 1240dba7b0efSSimon J. Gerraty ldir = Var_Value(SCOPE_GLOBAL, lcwd_vname); 124106b9b3e0SSimon J. Gerraty if (ldir.str != NULL) { 124206b9b3e0SSimon J. Gerraty strlcpy(lcwd, ldir.str, sizeof lcwd); 124306b9b3e0SSimon J. Gerraty FStr_Done(&ldir); 1244db29cad8SSimon J. Gerraty } 12453955d011SMarcel Moolenaar } 12463955d011SMarcel Moolenaar /* Skip past the pid. */ 12473955d011SMarcel Moolenaar if (strsep(&p, " ") == NULL) 12483955d011SMarcel Moolenaar continue; 12493955d011SMarcel Moolenaar #ifdef DEBUG_META_MODE 12503955d011SMarcel Moolenaar if (DEBUG(META)) 12519f45a3c8SSimon J. Gerraty debug_printf("%s: %u: %d: %c: cwd=%s lcwd=%s ldir=%s\n", 1252db29cad8SSimon J. Gerraty fname, lineno, 1253db29cad8SSimon J. Gerraty pid, buf[0], cwd, lcwd, latestdir); 12543955d011SMarcel Moolenaar #endif 12553955d011SMarcel Moolenaar break; 12563955d011SMarcel Moolenaar } 12573955d011SMarcel Moolenaar 12583955d011SMarcel Moolenaar CHECK_VALID_META(p); 12593955d011SMarcel Moolenaar 12603955d011SMarcel Moolenaar /* Process according to record type. */ 12613955d011SMarcel Moolenaar switch (buf[0]) { 12623955d011SMarcel Moolenaar case 'X': /* eXit */ 12639f45a3c8SSimon J. Gerraty Var_Delete(SCOPE_GLOBAL, lcwd_vname); 12649f45a3c8SSimon J. Gerraty Var_Delete(SCOPE_GLOBAL, ldir_vname); 12653955d011SMarcel Moolenaar lastpid = 0; /* no need to save ldir_vname */ 12663955d011SMarcel Moolenaar break; 12673955d011SMarcel Moolenaar 12683955d011SMarcel Moolenaar case 'F': /* [v]Fork */ 12693955d011SMarcel Moolenaar { 12703955d011SMarcel Moolenaar char cldir[64]; 12713955d011SMarcel Moolenaar int child; 12723955d011SMarcel Moolenaar 12733955d011SMarcel Moolenaar child = atoi(p); 12743955d011SMarcel Moolenaar if (child > 0) { 1275e2eeea75SSimon J. Gerraty snprintf(cldir, sizeof cldir, LCWD_VNAME_FMT, child); 12769f45a3c8SSimon J. Gerraty Global_Set(cldir, lcwd); 1277e2eeea75SSimon J. Gerraty snprintf(cldir, sizeof cldir, LDIR_VNAME_FMT, child); 12789f45a3c8SSimon J. Gerraty Global_Set(cldir, latestdir); 1279db29cad8SSimon J. Gerraty #ifdef DEBUG_META_MODE 1280db29cad8SSimon J. Gerraty if (DEBUG(META)) 1281956e45f6SSimon J. Gerraty debug_printf( 12829f45a3c8SSimon J. Gerraty "%s: %u: %d: cwd=%s lcwd=%s ldir=%s\n", 1283db29cad8SSimon J. Gerraty fname, lineno, 1284db29cad8SSimon J. Gerraty child, cwd, lcwd, latestdir); 1285db29cad8SSimon J. Gerraty #endif 12863955d011SMarcel Moolenaar } 12873955d011SMarcel Moolenaar } 12883955d011SMarcel Moolenaar break; 12893955d011SMarcel Moolenaar 12903955d011SMarcel Moolenaar case 'C': /* Chdir */ 1291db29cad8SSimon J. Gerraty /* Update lcwd and latest directory. */ 1292e2eeea75SSimon J. Gerraty strlcpy(latestdir, p, sizeof latestdir); 1293e2eeea75SSimon J. Gerraty strlcpy(lcwd, p, sizeof lcwd); 12949f45a3c8SSimon J. Gerraty Global_Set(lcwd_vname, lcwd); 12959f45a3c8SSimon J. Gerraty Global_Set(ldir_vname, lcwd); 1296db29cad8SSimon J. Gerraty #ifdef DEBUG_META_MODE 12979f45a3c8SSimon J. Gerraty DEBUG4(META, "%s: %u: cwd=%s ldir=%s\n", 1298956e45f6SSimon J. Gerraty fname, lineno, cwd, lcwd); 1299db29cad8SSimon J. Gerraty #endif 13003955d011SMarcel Moolenaar break; 13013955d011SMarcel Moolenaar 13023955d011SMarcel Moolenaar case 'M': /* renaMe */ 13030dede8b0SSimon J. Gerraty /* 13040dede8b0SSimon J. Gerraty * For 'M'oves we want to check 13050dede8b0SSimon J. Gerraty * the src as for 'R'ead 13060dede8b0SSimon J. Gerraty * and the target as for 'W'rite. 13070dede8b0SSimon J. Gerraty */ 130806b9b3e0SSimon J. Gerraty { 130906b9b3e0SSimon J. Gerraty char *cp = p; /* save this for a second */ 13100dede8b0SSimon J. Gerraty /* now get target */ 13110dede8b0SSimon J. Gerraty if (strsep(&p, " ") == NULL) 13120dede8b0SSimon J. Gerraty continue; 13130dede8b0SSimon J. Gerraty CHECK_VALID_META(p); 13140dede8b0SSimon J. Gerraty move_target = p; 13150dede8b0SSimon J. Gerraty p = cp; 131606b9b3e0SSimon J. Gerraty } 13173955d011SMarcel Moolenaar /* 'L' and 'M' put single quotes around the args */ 13180dede8b0SSimon J. Gerraty DEQUOTE(p); 13190dede8b0SSimon J. Gerraty DEQUOTE(move_target); 13203955d011SMarcel Moolenaar /* FALLTHROUGH */ 13213955d011SMarcel Moolenaar case 'D': /* unlink */ 1322956e45f6SSimon J. Gerraty if (*p == '/') { 132395e3ed2cSSimon J. Gerraty /* remove any missingFiles entries that match p */ 132406b9b3e0SSimon J. Gerraty StringListNode *ln = missingFiles.first; 1325956e45f6SSimon J. Gerraty while (ln != NULL) { 1326956e45f6SSimon J. Gerraty StringListNode *next = ln->next; 1327956e45f6SSimon J. Gerraty if (path_starts_with(ln->datum, p)) { 1328956e45f6SSimon J. Gerraty free(ln->datum); 132906b9b3e0SSimon J. Gerraty Lst_Remove(&missingFiles, ln); 1330956e45f6SSimon J. Gerraty } 1331956e45f6SSimon J. Gerraty ln = next; 13323955d011SMarcel Moolenaar } 13333955d011SMarcel Moolenaar } 13340dede8b0SSimon J. Gerraty if (buf[0] == 'M') { 13350dede8b0SSimon J. Gerraty /* the target of the mv is a file 'W'ritten */ 13360dede8b0SSimon J. Gerraty #ifdef DEBUG_META_MODE 1337956e45f6SSimon J. Gerraty DEBUG2(META, "meta_oodate: M %s -> %s\n", 13380dede8b0SSimon J. Gerraty p, move_target); 13390dede8b0SSimon J. Gerraty #endif 13400dede8b0SSimon J. Gerraty p = move_target; 13410dede8b0SSimon J. Gerraty goto check_write; 13420dede8b0SSimon J. Gerraty } 13433955d011SMarcel Moolenaar break; 13443955d011SMarcel Moolenaar case 'L': /* Link */ 13450dede8b0SSimon J. Gerraty /* 13460dede8b0SSimon J. Gerraty * For 'L'inks check 13470dede8b0SSimon J. Gerraty * the src as for 'R'ead 13480dede8b0SSimon J. Gerraty * and the target as for 'W'rite. 13490dede8b0SSimon J. Gerraty */ 13500dede8b0SSimon J. Gerraty link_src = p; 13510dede8b0SSimon J. Gerraty /* now get target */ 13523955d011SMarcel Moolenaar if (strsep(&p, " ") == NULL) 13533955d011SMarcel Moolenaar continue; 13543955d011SMarcel Moolenaar CHECK_VALID_META(p); 13553955d011SMarcel Moolenaar /* 'L' and 'M' put single quotes around the args */ 13560dede8b0SSimon J. Gerraty DEQUOTE(p); 13570dede8b0SSimon J. Gerraty DEQUOTE(link_src); 13580dede8b0SSimon J. Gerraty #ifdef DEBUG_META_MODE 1359956e45f6SSimon J. Gerraty DEBUG2(META, "meta_oodate: L %s -> %s\n", link_src, p); 13600dede8b0SSimon J. Gerraty #endif 13613955d011SMarcel Moolenaar /* FALLTHROUGH */ 13623955d011SMarcel Moolenaar case 'W': /* Write */ 13630dede8b0SSimon J. Gerraty check_write: 13643955d011SMarcel Moolenaar /* 13653955d011SMarcel Moolenaar * If a file we generated within our bailiwick 13663955d011SMarcel Moolenaar * but outside of .OBJDIR is missing, 13673955d011SMarcel Moolenaar * we need to do it again. 13683955d011SMarcel Moolenaar */ 13693955d011SMarcel Moolenaar /* ignore non-absolute paths */ 13703955d011SMarcel Moolenaar if (*p != '/') 13713955d011SMarcel Moolenaar break; 13723955d011SMarcel Moolenaar 137306b9b3e0SSimon J. Gerraty if (Lst_IsEmpty(&metaBailiwick)) 13743955d011SMarcel Moolenaar break; 13753955d011SMarcel Moolenaar 13763955d011SMarcel Moolenaar /* ignore cwd - normal dependencies handle those */ 13773955d011SMarcel Moolenaar if (strncmp(p, cwd, cwdlen) == 0) 13783955d011SMarcel Moolenaar break; 13793955d011SMarcel Moolenaar 138006b9b3e0SSimon J. Gerraty if (!has_any_prefix(p, &metaBailiwick)) 13813955d011SMarcel Moolenaar break; 13823955d011SMarcel Moolenaar 13833955d011SMarcel Moolenaar /* tmpdir might be within */ 13843955d011SMarcel Moolenaar if (tmplen > 0 && strncmp(p, tmpdir, tmplen) == 0) 13853955d011SMarcel Moolenaar break; 13863955d011SMarcel Moolenaar 13873955d011SMarcel Moolenaar /* ignore anything containing the string "tmp" */ 1388e2eeea75SSimon J. Gerraty /* XXX: The arguments to strstr must be swapped. */ 138906b9b3e0SSimon J. Gerraty if (strstr("tmp", p) != NULL) 13903955d011SMarcel Moolenaar break; 13913955d011SMarcel Moolenaar 1392e2eeea75SSimon J. Gerraty if ((link_src != NULL && cached_lstat(p, &cst) < 0) || 1393e2eeea75SSimon J. Gerraty (link_src == NULL && cached_stat(p, &cst) < 0)) { 1394956e45f6SSimon J. Gerraty if (!meta_ignore(gn, p)) 139506b9b3e0SSimon J. Gerraty append_if_new(&missingFiles, p); 139695e3ed2cSSimon J. Gerraty } 13973955d011SMarcel Moolenaar break; 13980dede8b0SSimon J. Gerraty check_link_src: 13990dede8b0SSimon J. Gerraty p = link_src; 14000dede8b0SSimon J. Gerraty link_src = NULL; 14010dede8b0SSimon J. Gerraty #ifdef DEBUG_META_MODE 1402956e45f6SSimon J. Gerraty DEBUG1(META, "meta_oodate: L src %s\n", p); 14030dede8b0SSimon J. Gerraty #endif 14040dede8b0SSimon J. Gerraty /* FALLTHROUGH */ 14053955d011SMarcel Moolenaar case 'R': /* Read */ 14063955d011SMarcel Moolenaar case 'E': /* Exec */ 14073955d011SMarcel Moolenaar /* 14083955d011SMarcel Moolenaar * Check for runtime files that can't 14093955d011SMarcel Moolenaar * be part of the dependencies because 14103955d011SMarcel Moolenaar * they are _expected_ to change. 14113955d011SMarcel Moolenaar */ 141295e3ed2cSSimon J. Gerraty if (meta_ignore(gn, p)) 14133955d011SMarcel Moolenaar break; 14143955d011SMarcel Moolenaar 14153955d011SMarcel Moolenaar /* 14163955d011SMarcel Moolenaar * The rest of the record is the file name. 14173955d011SMarcel Moolenaar * Check if it's not an absolute path. 14183955d011SMarcel Moolenaar */ 14193955d011SMarcel Moolenaar { 14203955d011SMarcel Moolenaar char *sdirs[4]; 14213955d011SMarcel Moolenaar char **sdp; 14223955d011SMarcel Moolenaar int sdx = 0; 1423b0c40a00SSimon J. Gerraty bool found = false; 14243955d011SMarcel Moolenaar 14253955d011SMarcel Moolenaar if (*p == '/') { 14263955d011SMarcel Moolenaar sdirs[sdx++] = p; /* done */ 14273955d011SMarcel Moolenaar } else { 14283955d011SMarcel Moolenaar if (strcmp(".", p) == 0) 14293955d011SMarcel Moolenaar continue; /* no point */ 14303955d011SMarcel Moolenaar 14313955d011SMarcel Moolenaar /* Check vs latestdir */ 14324fde40d9SSimon J. Gerraty if (snprintf(fname1, sizeof fname1, "%s/%s", latestdir, p) < (int)(sizeof fname1)) 14333955d011SMarcel Moolenaar sdirs[sdx++] = fname1; 14343955d011SMarcel Moolenaar 1435db29cad8SSimon J. Gerraty if (strcmp(latestdir, lcwd) != 0) { 1436db29cad8SSimon J. Gerraty /* Check vs lcwd */ 14374fde40d9SSimon J. Gerraty if (snprintf(fname2, sizeof fname2, "%s/%s", lcwd, p) < (int)(sizeof fname2)) 14383955d011SMarcel Moolenaar sdirs[sdx++] = fname2; 14393955d011SMarcel Moolenaar } 1440db29cad8SSimon J. Gerraty if (strcmp(lcwd, cwd) != 0) { 1441db29cad8SSimon J. Gerraty /* Check vs cwd */ 14424fde40d9SSimon J. Gerraty if (snprintf(fname3, sizeof fname3, "%s/%s", cwd, p) < (int)(sizeof fname3)) 1443db29cad8SSimon J. Gerraty sdirs[sdx++] = fname3; 1444db29cad8SSimon J. Gerraty } 14453955d011SMarcel Moolenaar } 14463955d011SMarcel Moolenaar sdirs[sdx++] = NULL; 14473955d011SMarcel Moolenaar 144806b9b3e0SSimon J. Gerraty for (sdp = sdirs; *sdp != NULL && !found; sdp++) { 14493955d011SMarcel Moolenaar #ifdef DEBUG_META_MODE 14509f45a3c8SSimon J. Gerraty DEBUG3(META, "%s: %u: looking for: %s\n", 1451956e45f6SSimon J. Gerraty fname, lineno, *sdp); 14523955d011SMarcel Moolenaar #endif 1453e2eeea75SSimon J. Gerraty if (cached_stat(*sdp, &cst) == 0) { 1454b0c40a00SSimon J. Gerraty found = true; 14553955d011SMarcel Moolenaar p = *sdp; 14563955d011SMarcel Moolenaar } 14573955d011SMarcel Moolenaar } 14583955d011SMarcel Moolenaar if (found) { 14593955d011SMarcel Moolenaar #ifdef DEBUG_META_MODE 14609f45a3c8SSimon J. Gerraty DEBUG3(META, "%s: %u: found: %s\n", 1461956e45f6SSimon J. Gerraty fname, lineno, p); 14623955d011SMarcel Moolenaar #endif 1463e2eeea75SSimon J. Gerraty if (!S_ISDIR(cst.cst_mode) && 1464e2eeea75SSimon J. Gerraty cst.cst_mtime > gn->mtime) { 14659f45a3c8SSimon J. Gerraty DEBUG3(META, "%s: %u: file '%s' is newer than the target...\n", 1466956e45f6SSimon J. Gerraty fname, lineno, p); 1467b0c40a00SSimon J. Gerraty oodate = true; 1468e2eeea75SSimon J. Gerraty } else if (S_ISDIR(cst.cst_mode)) { 14693955d011SMarcel Moolenaar /* Update the latest directory. */ 1470b778b302SSimon J. Gerraty cached_realpath(p, latestdir); 14713955d011SMarcel Moolenaar } 14723955d011SMarcel Moolenaar } else if (errno == ENOENT && *p == '/' && 14733955d011SMarcel Moolenaar strncmp(p, cwd, cwdlen) != 0) { 14743955d011SMarcel Moolenaar /* 14753955d011SMarcel Moolenaar * A referenced file outside of CWD is missing. 14763955d011SMarcel Moolenaar * We cannot catch every eventuality here... 14773955d011SMarcel Moolenaar */ 147806b9b3e0SSimon J. Gerraty append_if_new(&missingFiles, p); 14793955d011SMarcel Moolenaar } 14803955d011SMarcel Moolenaar } 1481db29cad8SSimon J. Gerraty if (buf[0] == 'E') { 1482db29cad8SSimon J. Gerraty /* previous latestdir is no longer relevant */ 1483e2eeea75SSimon J. Gerraty strlcpy(latestdir, lcwd, sizeof latestdir); 1484db29cad8SSimon J. Gerraty } 14853955d011SMarcel Moolenaar break; 14863955d011SMarcel Moolenaar default: 14873955d011SMarcel Moolenaar break; 14883955d011SMarcel Moolenaar } 14890dede8b0SSimon J. Gerraty if (!oodate && buf[0] == 'L' && link_src != NULL) 14900dede8b0SSimon J. Gerraty goto check_link_src; 14913955d011SMarcel Moolenaar } else if (strcmp(buf, "CMD") == 0) { 14923955d011SMarcel Moolenaar /* 14933955d011SMarcel Moolenaar * Compare the current command with the one in the 14943955d011SMarcel Moolenaar * meta data file. 14953955d011SMarcel Moolenaar */ 1496956e45f6SSimon J. Gerraty if (cmdNode == NULL) { 14979f45a3c8SSimon J. Gerraty DEBUG2(META, "%s: %u: there were more build commands in the meta data file than there are now...\n", 1498956e45f6SSimon J. Gerraty fname, lineno); 1499b0c40a00SSimon J. Gerraty oodate = true; 15003955d011SMarcel Moolenaar } else { 150106b9b3e0SSimon J. Gerraty const char *cp; 1502956e45f6SSimon J. Gerraty char *cmd = cmdNode->datum; 1503b0c40a00SSimon J. Gerraty bool hasOODATE = false; 15043955d011SMarcel Moolenaar 150506b9b3e0SSimon J. Gerraty if (strstr(cmd, "$?") != NULL) 1506b0c40a00SSimon J. Gerraty hasOODATE = true; 150706b9b3e0SSimon J. Gerraty else if ((cp = strstr(cmd, ".OODATE")) != NULL) { 15081748de26SSimon J. Gerraty /* check for $[{(].OODATE[:)}] */ 15093955d011SMarcel Moolenaar if (cp > cmd + 2 && cp[-2] == '$') 1510b0c40a00SSimon J. Gerraty hasOODATE = true; 15113955d011SMarcel Moolenaar } 15121748de26SSimon J. Gerraty if (hasOODATE) { 1513b0c40a00SSimon J. Gerraty needOODATE = true; 15149f45a3c8SSimon J. Gerraty DEBUG2(META, "%s: %u: cannot compare command using .OODATE\n", 1515956e45f6SSimon J. Gerraty fname, lineno); 15163955d011SMarcel Moolenaar } 15178c973ee2SSimon J. Gerraty cmd = Var_Subst(cmd, gn, VARE_UNDEFERR); 1518956e45f6SSimon J. Gerraty /* TODO: handle errors */ 15193955d011SMarcel Moolenaar 152006b9b3e0SSimon J. Gerraty if ((cp = strchr(cmd, '\n')) != NULL) { 15213955d011SMarcel Moolenaar int n; 15223955d011SMarcel Moolenaar 15233955d011SMarcel Moolenaar /* 15243955d011SMarcel Moolenaar * This command contains newlines, we need to 15253955d011SMarcel Moolenaar * fetch more from the .meta file before we 15263955d011SMarcel Moolenaar * attempt a comparison. 15273955d011SMarcel Moolenaar */ 15283955d011SMarcel Moolenaar /* first put the newline back at buf[x - 1] */ 15293955d011SMarcel Moolenaar buf[x - 1] = '\n'; 15303955d011SMarcel Moolenaar do { 15313955d011SMarcel Moolenaar /* now fetch the next line */ 15323955d011SMarcel Moolenaar if ((n = fgetLine(&buf, &bufsz, x, fp)) <= 0) 15333955d011SMarcel Moolenaar break; 15343955d011SMarcel Moolenaar x = n; 15353955d011SMarcel Moolenaar lineno++; 15363955d011SMarcel Moolenaar if (buf[x - 1] != '\n') { 15379f45a3c8SSimon J. Gerraty warnx("%s: %u: line truncated at %u", fname, lineno, x); 15383955d011SMarcel Moolenaar break; 15393955d011SMarcel Moolenaar } 154006b9b3e0SSimon J. Gerraty cp = strchr(cp + 1, '\n'); 154106b9b3e0SSimon J. Gerraty } while (cp != NULL); 15423955d011SMarcel Moolenaar if (buf[x - 1] == '\n') 15433955d011SMarcel Moolenaar buf[x - 1] = '\0'; 15443955d011SMarcel Moolenaar } 1545e2eeea75SSimon J. Gerraty if (p != NULL && 154649caa483SSimon J. Gerraty !hasOODATE && 15473955d011SMarcel Moolenaar !(gn->type & OP_NOMETA_CMP) && 15489f45a3c8SSimon J. Gerraty (meta_cmd_cmp(gn, p, cmd, cmp_filter) != 0)) { 15499f45a3c8SSimon J. Gerraty DEBUG4(META, "%s: %u: a build command has changed\n%s\nvs\n%s\n", 1550956e45f6SSimon J. Gerraty fname, lineno, p, cmd); 15513955d011SMarcel Moolenaar if (!metaIgnoreCMDs) 1552b0c40a00SSimon J. Gerraty oodate = true; 15533955d011SMarcel Moolenaar } 15543955d011SMarcel Moolenaar free(cmd); 1555956e45f6SSimon J. Gerraty cmdNode = cmdNode->next; 15563955d011SMarcel Moolenaar } 15573955d011SMarcel Moolenaar } else if (strcmp(buf, "CWD") == 0) { 15583955d011SMarcel Moolenaar /* 15593955d011SMarcel Moolenaar * Check if there are extra commands now 15603955d011SMarcel Moolenaar * that weren't in the meta data file. 15613955d011SMarcel Moolenaar */ 1562956e45f6SSimon J. Gerraty if (!oodate && cmdNode != NULL) { 15639f45a3c8SSimon J. Gerraty DEBUG2(META, "%s: %u: there are extra build commands now that weren't in the meta data file\n", 1564956e45f6SSimon J. Gerraty fname, lineno); 1565b0c40a00SSimon J. Gerraty oodate = true; 15663955d011SMarcel Moolenaar } 156749caa483SSimon J. Gerraty CHECK_VALID_META(p); 15683955d011SMarcel Moolenaar if (strcmp(p, cwd) != 0) { 15699f45a3c8SSimon J. Gerraty DEBUG4(META, "%s: %u: the current working directory has changed from '%s' to '%s'\n", 1570956e45f6SSimon J. Gerraty fname, lineno, p, curdir); 1571b0c40a00SSimon J. Gerraty oodate = true; 15723955d011SMarcel Moolenaar } 15733955d011SMarcel Moolenaar } 15743955d011SMarcel Moolenaar } 15753955d011SMarcel Moolenaar 15763955d011SMarcel Moolenaar fclose(fp); 157706b9b3e0SSimon J. Gerraty if (!Lst_IsEmpty(&missingFiles)) { 1578956e45f6SSimon J. Gerraty DEBUG2(META, "%s: missing files: %s...\n", 157906b9b3e0SSimon J. Gerraty fname, (char *)missingFiles.first->datum); 1580b0c40a00SSimon J. Gerraty oodate = true; 15813955d011SMarcel Moolenaar } 1582b778b302SSimon J. Gerraty if (!oodate && !have_filemon && filemonMissing) { 1583956e45f6SSimon J. Gerraty DEBUG1(META, "%s: missing filemon data\n", fname); 1584b0c40a00SSimon J. Gerraty oodate = true; 1585b778b302SSimon J. Gerraty } 15863955d011SMarcel Moolenaar } else { 15873841c287SSimon J. Gerraty if (writeMeta && (metaMissing || (gn->type & OP_META))) { 158806b9b3e0SSimon J. Gerraty const char *cp = NULL; 1589b778b302SSimon J. Gerraty 1590b778b302SSimon J. Gerraty /* if target is in .CURDIR we do not need a meta file */ 159106b9b3e0SSimon J. Gerraty if (gn->path != NULL && (cp = strrchr(gn->path, '/')) != NULL && 159206b9b3e0SSimon J. Gerraty (cp > gn->path)) { 1593956e45f6SSimon J. Gerraty if (strncmp(curdir, gn->path, (size_t)(cp - gn->path)) != 0) { 1594b778b302SSimon J. Gerraty cp = NULL; /* not in .CURDIR */ 1595b778b302SSimon J. Gerraty } 1596b778b302SSimon J. Gerraty } 1597e2eeea75SSimon J. Gerraty if (cp == NULL) { 1598956e45f6SSimon J. Gerraty DEBUG1(META, "%s: required but missing\n", fname); 1599b0c40a00SSimon J. Gerraty oodate = true; 1600b0c40a00SSimon J. Gerraty needOODATE = true; /* assume the worst */ 16013955d011SMarcel Moolenaar } 16023955d011SMarcel Moolenaar } 1603b778b302SSimon J. Gerraty } 1604be19d90bSSimon J. Gerraty 160506b9b3e0SSimon J. Gerraty Lst_DoneCall(&missingFiles, free); 1606be19d90bSSimon J. Gerraty 16073cbdda60SSimon J. Gerraty if (oodate && needOODATE) { 16083955d011SMarcel Moolenaar /* 16093cbdda60SSimon J. Gerraty * Target uses .OODATE which is empty; or we wouldn't be here. 16103cbdda60SSimon J. Gerraty * We have decided it is oodate, so .OODATE needs to be set. 16113cbdda60SSimon J. Gerraty * All we can sanely do is set it to .ALLSRC. 16123955d011SMarcel Moolenaar */ 1613dba7b0efSSimon J. Gerraty Var_Delete(gn, OODATE); 1614dba7b0efSSimon J. Gerraty Var_Set(gn, OODATE, GNode_VarAllsrc(gn)); 16153955d011SMarcel Moolenaar } 1616b778b302SSimon J. Gerraty 1617b778b302SSimon J. Gerraty oodate_out: 161806b9b3e0SSimon J. Gerraty FStr_Done(&dname); 16193955d011SMarcel Moolenaar return oodate; 16203955d011SMarcel Moolenaar } 16213955d011SMarcel Moolenaar 16223955d011SMarcel Moolenaar /* support for compat mode */ 16233955d011SMarcel Moolenaar 16243955d011SMarcel Moolenaar static int childPipe[2]; 16253955d011SMarcel Moolenaar 16263955d011SMarcel Moolenaar void 16273955d011SMarcel Moolenaar meta_compat_start(void) 16283955d011SMarcel Moolenaar { 16293955d011SMarcel Moolenaar #ifdef USE_FILEMON_ONCE 16303955d011SMarcel Moolenaar /* 16313955d011SMarcel Moolenaar * We need to re-open filemon for each cmd. 16323955d011SMarcel Moolenaar */ 16333955d011SMarcel Moolenaar BuildMon *pbm = &Mybm; 16343955d011SMarcel Moolenaar 16353955d011SMarcel Moolenaar if (pbm->mfp != NULL && useFilemon) { 163649caa483SSimon J. Gerraty meta_open_filemon(pbm); 16373955d011SMarcel Moolenaar } else { 163849caa483SSimon J. Gerraty pbm->mon_fd = -1; 163949caa483SSimon J. Gerraty pbm->filemon = NULL; 16403955d011SMarcel Moolenaar } 16413955d011SMarcel Moolenaar #endif 16423955d011SMarcel Moolenaar if (pipe(childPipe) < 0) 16433955d011SMarcel Moolenaar Punt("Cannot create pipe: %s", strerror(errno)); 16443955d011SMarcel Moolenaar /* Set close-on-exec flag for both */ 1645be19d90bSSimon J. Gerraty (void)fcntl(childPipe[0], F_SETFD, FD_CLOEXEC); 1646be19d90bSSimon J. Gerraty (void)fcntl(childPipe[1], F_SETFD, FD_CLOEXEC); 16473955d011SMarcel Moolenaar } 16483955d011SMarcel Moolenaar 16493955d011SMarcel Moolenaar void 16503955d011SMarcel Moolenaar meta_compat_child(void) 16513955d011SMarcel Moolenaar { 16523955d011SMarcel Moolenaar meta_job_child(NULL); 1653956e45f6SSimon J. Gerraty if (dup2(childPipe[1], 1) < 0 || dup2(1, 2) < 0) 1654956e45f6SSimon J. Gerraty execDie("dup2", "pipe"); 16553955d011SMarcel Moolenaar } 16563955d011SMarcel Moolenaar 16573955d011SMarcel Moolenaar void 165849caa483SSimon J. Gerraty meta_compat_parent(pid_t child) 16593955d011SMarcel Moolenaar { 166049caa483SSimon J. Gerraty int outfd, metafd, maxfd, nfds; 166149caa483SSimon J. Gerraty char buf[BUFSIZ+1]; 166249caa483SSimon J. Gerraty fd_set readfds; 16633955d011SMarcel Moolenaar 166449caa483SSimon J. Gerraty meta_job_parent(NULL, child); 16653955d011SMarcel Moolenaar close(childPipe[1]); /* child side */ 166649caa483SSimon J. Gerraty outfd = childPipe[0]; 166749caa483SSimon J. Gerraty #ifdef USE_FILEMON 166806b9b3e0SSimon J. Gerraty metafd = Mybm.filemon != NULL ? filemon_readfd(Mybm.filemon) : -1; 166949caa483SSimon J. Gerraty #else 167049caa483SSimon J. Gerraty metafd = -1; 167149caa483SSimon J. Gerraty #endif 167249caa483SSimon J. Gerraty maxfd = -1; 167349caa483SSimon J. Gerraty if (outfd > maxfd) 167449caa483SSimon J. Gerraty maxfd = outfd; 167549caa483SSimon J. Gerraty if (metafd > maxfd) 167649caa483SSimon J. Gerraty maxfd = metafd; 167749caa483SSimon J. Gerraty 167849caa483SSimon J. Gerraty while (outfd != -1 || metafd != -1) { 167949caa483SSimon J. Gerraty FD_ZERO(&readfds); 168049caa483SSimon J. Gerraty if (outfd != -1) { 168149caa483SSimon J. Gerraty FD_SET(outfd, &readfds); 16823955d011SMarcel Moolenaar } 168349caa483SSimon J. Gerraty if (metafd != -1) { 168449caa483SSimon J. Gerraty FD_SET(metafd, &readfds); 168549caa483SSimon J. Gerraty } 168649caa483SSimon J. Gerraty nfds = select(maxfd + 1, &readfds, NULL, NULL, NULL); 168749caa483SSimon J. Gerraty if (nfds == -1) { 168849caa483SSimon J. Gerraty if (errno == EINTR) 168949caa483SSimon J. Gerraty continue; 169049caa483SSimon J. Gerraty err(1, "select"); 169149caa483SSimon J. Gerraty } 169249caa483SSimon J. Gerraty 169306b9b3e0SSimon J. Gerraty if (outfd != -1 && FD_ISSET(outfd, &readfds) != 0) do { 169449caa483SSimon J. Gerraty /* XXX this is not line-buffered */ 1695e2eeea75SSimon J. Gerraty ssize_t nread = read(outfd, buf, sizeof buf - 1); 169649caa483SSimon J. Gerraty if (nread == -1) 169749caa483SSimon J. Gerraty err(1, "read"); 169849caa483SSimon J. Gerraty if (nread == 0) { 169949caa483SSimon J. Gerraty close(outfd); 170049caa483SSimon J. Gerraty outfd = -1; 170149caa483SSimon J. Gerraty break; 170249caa483SSimon J. Gerraty } 170349caa483SSimon J. Gerraty fwrite(buf, 1, (size_t)nread, stdout); 170449caa483SSimon J. Gerraty fflush(stdout); 170549caa483SSimon J. Gerraty buf[nread] = '\0'; 170649caa483SSimon J. Gerraty meta_job_output(NULL, buf, ""); 170712904384SSimon J. Gerraty } while (false); 170806b9b3e0SSimon J. Gerraty if (metafd != -1 && FD_ISSET(metafd, &readfds) != 0) { 170949caa483SSimon J. Gerraty if (meta_job_event(NULL) <= 0) 171049caa483SSimon J. Gerraty metafd = -1; 171149caa483SSimon J. Gerraty } 171249caa483SSimon J. Gerraty } 17133955d011SMarcel Moolenaar } 17143955d011SMarcel Moolenaar 17153955d011SMarcel Moolenaar #endif /* USE_META */ 1716