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