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