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