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