Sat Apr 11 05:24:30 2015 UTC ()
Use separate vars to track cwd and last dir a process read.


(sjg)
diff -r1.37 -r1.38 src/usr.bin/make/meta.c

cvs diff -r1.37 -r1.38 src/usr.bin/make/meta.c (switch to unified diff)

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