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