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