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