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