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