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